摘要
本文借助典型商务 Android* 应用中的图表就展示数据和分析的不同选择进行讨论。 讨论的内容包括某个解决方案相比其他解决方案的优势和劣势,以及在选择图表库或 API 时其他技术方面的考虑。 最后,我们还将详细讨论如何使用常用的 AChartEngine* 库在 Android 本地添加饼形图,折线图和柱状图。
目录
摘要
Android 应用图表选项和考量
AChartEngine 概览与运用
零售饭店样例应用– Little Chef (小厨师)
以饼形图形式展示菜单类别
采用折线图呈现销售趋势
采用柱状图进行销售比较
在一个活动中嵌入多个图表
总结
Android 应用图表选项和考量
如果你希望在应用中展示数据或分析,良好的视觉效果至关重要。 它能够对用户满意度产生重大影响。 选择合适类型的图表同样至关重要。
对于 Android 应用,现在暂时没有标准或者平台库来展示图表。 根据应用的不同要求,我们可以采用类似于 Google Charts* 的基于 Web 的图表库,但是这需要应用保持在线并能够使用 Google Charts API 来展示图表。 如果您的应用依赖于其他要求可访问网络的 Google 服务,那么 Google Chart API 无疑是您的理想选择。 Google Charts 链接如下。
https://developers.google.com/chart/
以下链接是拥有多种类型可用图表的综合图库。
https://google-developers.appspot.com/chart/interactive/docs/gallery
如果你能够熟练使用 HTML5,那么图表的选择将更加广泛。 有些 HTML5 库可使用应用进行打包,因而同样成为可离线访问的理想选择。 如果你希望开发一款跨平台应用,这将是一个很好的选择。 下列文章包括一个此类型的库。
/en-us/android/articles/develop-html5-chart-applications-for-android-and-win8-devices
在最终确定某基于 Web 或离线 HTML5 图库之前,你也许会考虑常托管这些解决方案的 Android WebView* 的局限性。
http://developer.android.com/guide/webapps/webview.html
其他需要考虑的技术因素有性能、高级图表自定义功能、支持完整的 Android API、自定义用户交互(如手势)或其他可用性问题。 上述某些库可能不具备这些功能。 低水平的高级自定义功能仅限于本地 Android 解决方案,有时需要直接与 OpenGL/GPU 进行编程,这取决于您的应用要求。
基于 Web 或 HTML5 解决方案有时无法满足您的应用需求,或者您希望使用老式 Android 视图和活动在本地完成图表。 这种方式使您的应用能够与 Android 应用的其他组件紧密集成,从而根据需要无缝实现在活动或图表组件之间协调、共享、持久存储和恢复数据的功能。 此外,还可根据需要支持您的应用执行高级的低水平图表自定义功能。 另一大优势是灵活性以及在本地 Android 图表组件中直接访问全部 Android API 的功能。
有多个第三方库可以用来将图表添加至您的 Android 应用之中。 AChartEngine正是这样的一个库,它现在在社区参与和应用方面受到了 Android 开发人员的普遍欢迎。
https://code.google.com/p/achartengine/
它正处于积极开发的阶段,并且支持多种图表类型。 在本文中,我们将使用这个库来展示如何将基本图表(饼形图、折线图和柱状图)添加至您的 Android 应用之中。
AChartEngine 概览与运用
Android API 支持我们打造一款全新、成熟的图表解决方案。 AChartEngine实现了这一功能并且还具备更多其他功能。 作为受到普遍欢迎的本地图库之一,它面向具备完全成熟功能集的 Android。 支持多种图表类型,可根据需要自定义图表。 图表设有放大/缩小控制以及其他标准的图表功能。
AChartEngine的主要网站是 https://code.google.com/p/achartengine/
以下文章引用于主要网站,进行了更为深入细致的分析。
http://jaxenter.com/effort-free-graphs-on-android-with-achartengine-46199.html
AChartEngine拥有便捷的工厂类 ChartFactory,可根据需要返回在 Android 视图或活动中的图表。 该图表视图然后可以嵌入到其他活动中,类似于其他的 Android 视图。
AChartEngine库的安装与应用与其他 Android 库类似。 只需下载 jar 文件,并放入项目的库文件夹之中。 基于 Eclipse* 或者 Gradle* 的创建将自动编译并创建库。
借助 AChartEngine库创建图表的流程十分简单,而且对于不同的图表类型都能够保持统一。 我们可以根据以下基本步骤,创建简单的图表:
- 创建一系列数据集和渲染器。 AChartEngine具备定义的泛型类,可托管数据(如 XYMultipleSeriesDataset)和渲染器(如 XYMultipleSeriesRenderer)。
创建基本的折线图:
XYMultipleSeriesDataset mDataset;
XYMultipleSeriesRenderer mRenderer;
double[] xvals = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
double[] yvals = new double[]{25, 45, 50, 65, 80, 84, 96, 106, 123, 118, 134, 121};
XYSeries series = new XYSeries("Sales Data");
for (int i = 0; i < 12; i++)
series.add(xvals[i], yvals[i]);
XYSeriesRenderer renderer = new XYSeriesRenderer();
mDataset.addSeries(series);
mRenderer.addSeriesRenderer(renderer);
代码片段 1。 创建系列数据集和渲染器 ++
- 使用图表标题、颜色、点样式等其他自定义设置配置渲染器。 请注意,我们可以在单独的渲染器(对应某些数据系列)以及整个图表(如图表标题)上进行配置。 >
renderer.setColor(Color.GREEN);
renderer.setPointStyle(PointStyle.CIRCLE);
mRenderer.setChartTitle("Sales Trend Chart");
代码片段 2。 配置饼形图系列渲染器和主要渲染器 ++
- 采用内置的 ChartFactory类,并通过提供上述配置的多个系列的数据集和渲染器获得视图(或完全活动)图表。 请注意,你还需要在 Android 环境(从您的 Android 活动中)下传递。
mChartView = ChartFactory.getLineChartView(context, mDataset, mRenderer);
代码片段 3。 使用 ChartFactory ++
- 在 Android 活动布局 xml 中创建布局来存储图表,例如 LinearLayout,并将视图添加至布局。
layout = (LinearLayout) findViewById(R.id.chart);
layout.addView(mChartView);
代码片段 4。 添加图表至 Android 布局 ++
现在,基本的折线图已经创建完毕,该图嵌入在 Android 活动的线性布局内。
零售业饭店样例应用– Little Chef (小厨师)
为展示图表的运用,我们采用一款饭店样例应用 - Little Chef (小厨师)。
该应用支持用户通过不同的菜单类别和选择进行浏览。
![]()
图 1. 饭店样例应用– Little Chef (小厨师)
这款饭店应用可供厨师或者所有者查看以饼形图展示的不同菜单类别和选择,以折线图呈现的销售趋势,或者以柱状图展现的销售比较。 下列屏幕截图为图表视图:
![]()
图 2.饭店样例应用采用 AChartEngine 库来展示图表
在这款样例应用中,饭店所有者可从主页屏幕导航至图表视图。 根据需要,多个图表可嵌入同一个 Android 活动中,也可以每个图表单独嵌入一个活动中。
以饼形图形式展示菜单类别
为了演示饼形图的运用,我们将在每个类别中展示不同的菜单类别和项目数量。
首先,为 Android 布局中的图表定义占位符。 我们可以选择添加下列片段所示的题目标签。
<TextView
android:layout_width="261dp"
android:layout_height="104dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Menu Items Pie Chart"
android:gravity="center"
android:id="@+id/textView" /><LinearLayout
android:orientation="vertical"
android:layout_width="600dp"
android:layout_height="400dp"
android:id="@+id/chart1"
android:layout_gravity="center_horizontal"
android:background="@android:color/transparent"></LinearLayout>
代码片段 5。 样例应用 ++ 的饼形图布局
我们使用 ID "chart1"作为托管饼形图的线性布局的引用。
采用 AChartEngine绘制饼形图,还需使用 RoundChart。 “圆形”图表基本上与 XYChart类似,只是某些配置和设置有所不同。
如 AChartEngine的运用部分所描述,我们首先需要定义并初始化数据系列和渲染器。 针对饼形图,我们分别采用 CategorySeries和 DefaultRenderer类。 请参考下列代码片段。
int[] COLORS = new int[]{Color.GREEN, Color.BLUE, Color.MAGENTA, Color.CYAN};
CategorySeries mSeries = new CategorySeries("");
DefaultRenderer mRenderer = new DefaultRenderer();
Map<String, Integer> mcount = new HashMap<String, Integer>();
for (MenuFactory.MenuItem m : menuItems) {
if (!mcount.containsKey(m.category)) mcount.put(m.category, 1);
else mcount.put(m.category, mcount.get(m.category) + 1);
}
for (Map.Entry<String, Integer> m : mcount.entrySet()) {
mSeries.add(m.getKey(), m.getValue());
SimpleSeriesRenderer renderer = new SimpleSeriesRenderer();
renderer.setColor(COLORS[(mSeries.getItemCount() - 1) % COLORS.length]);
mRenderer.addSeriesRenderer(renderer);
}
mRenderer.setChartTitle("Menu Item Categories");
mRenderer.setLabelsColor(Color.BLACK);
代码片段 6. 样例应用 ++ 的饼形图数据初始化
如上述代码片段所示, SimpleSeriesRenderer用于渲染每个饼形图数据。 我们在该渲染器中配置饼形图每个部分的颜色。 所有的渲染器都添加至主要的渲染器对象。 在主要的渲染器对象中,配置标签的图表标题和颜色。
采用 ChartFactory 类来获得 Android 视图的饼形图,上下文传递、数据系列和渲染器对象。
mChartView = ChartFactory.getPieChartView(context, mSeries, mRenderer);
LinearLayout layout = (LinearLayout) findViewById(R.id.chart1);
layout.addView(mChartView);
代码片段 7。 在样例应用 ++ 中添加饼形图至 Android 布局中
最后,饼形图可以嵌入到如代码片段中所示的 chart1线性布局之中。
最终生成图表如下列屏幕截图所示。
![]()
图 3. 以饼形图形式展示菜单类别
采用折线图呈现销售趋势
在饭店样例应用中,我们可以以折线图形式展现去年的销售状况。
为 Android 布局中的图表定义占位符。 我们采用线性布局并分配一个 ID (如 chart2)。
<TextView
android:layout_width="268dp"
android:layout_height="104dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Sales Trend"
android:gravity="center"
android:id="@+id/textView2" /><LinearLayout
android:orientation="vertical"
android:layout_width="600dp"
android:layout_height="400dp"
android:id="@+id/chart2"
android:layout_gravity="center_horizontal"></LinearLayout>
代码片段 8。 样例应用 ++ 的折线图布局
采用 AChartEngine绘制饼形图,还需要使用 RoundChart。 “圆形”图表基本上与 XYChart类似,只是某些配置和设置有所不同。
定义并初始化数据系列和渲染器。 针对折线图,我们分别采用 XYMultipleSeriesDataset和 XYMultipleSeriesRenderer类。 请参考下列代码片段。
XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
double[] xvals = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
double[] yvals = new double[]{25, 45, 50, 65, 80, 84, 96, 106, 123, 118, 134, 121};
XYSeries series = new XYSeries("Sales Data");
for (int i = 0; i < 12; i++)
series.add(xvals[i], yvals[i]);
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setColor(Color.GREEN);
renderer.setPointStyle(PointStyle.CIRCLE);
renderer.setFillPoints(true);
renderer.setDisplayChartValues(true);
mDataset.addSeries(series);
mRenderer.addSeriesRenderer(renderer);
mRenderer.setChartTitle("Sales Trend Chart");
mRenderer.setXTitle("Month");
mRenderer.setYTitle("Sales in 1000s");
mRenderer.setXAxisMin(0.5);
mRenderer.setXAxisMax(12.5);
mRenderer.setYAxisMin(20);
mRenderer.setYAxisMax(140);
mRenderer.setAxesColor(Color.GRAY);
mRenderer.setLabelsColor(Color.LTGRAY);
mRenderer.setXLabels(1);
mRenderer.setYLabels(10);
mRenderer.addXTextLabel(1, "Jan");
mRenderer.addXTextLabel(3, "Mar");
mRenderer.addXTextLabel(5, "May");
mRenderer.addXTextLabel(7, "Jul");
mRenderer.addXTextLabel(10, "Oct");
mRenderer.addXTextLabel(12, "Dec");
代码片段 9. 本示例仅列举了面向样例应用 ++
样例销售数据的折线图数据集和渲染器设置,但是该应用能够请求抽象的后台数据库或者模型以返回销售数据。 代码片段展示了其他我们可添加至折线图中的自定义设置。 我们为月份添加了文本标签,并配置颜色和标题等。 对于所有的自定义设置,请参考代码片段。
采用 ChartFactory 类来获得 Android 视图的折线图,上下文传递、数据系列和渲染器对象。
mChartView = ChartFactory.getLineChartView(context, mDataset, mRenderer);
LinearLayout layout = (LinearLayout) findViewById(R.id.chart2);
layout.addView(mChartView);
Code Snippet 10. 在样例应用 ++ 中添加饼形图至 Android 布局中
最后,饼形图可以嵌入到如代码片段中所示的 chart1 线性布局之中。
最终生成图表如下列屏幕截图所示。
![]()
图 4. 采用折线图呈现销售趋势
采用柱状图进行销售比较
AChartEngine使我们能够根据需要添加更多的数据系列。 而且,我们还可以通过配置相应的渲染器来自定义每一个数据系列的外观。
添加柱状图的流程与之前所述图表类似。 我们将绘制两年的销售数据以进行比较。
与上述类似,在 Andoid 布局中为图表定义占位符。 我们采用线性布局,并分配一个 ID (如 chart3)。
<TextView
android:layout_width="344dp"
android:layout_height="122dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Sales Comparison Chart"
android:gravity="center"
android:id="@+id/textView3" /><LinearLayout
android:orientation="vertical"
android:layout_width="600dp"
android:layout_height="400dp"
android:id="@+id/chart3"
android:layout_gravity="center_horizontal"></LinearLayout>
代码片段 11。 样例应用 ++ 的柱状图布局
定义并初始化数据系列和渲染器。 与折线图类似,针对柱状图,我们分别采用 XYMultipleSeriesDataset和 XYMultipleSeriesRenderer类。 请参考以下代码片段。
XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
double[] xvals = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
double[] yvals = new double[]{25, 45, 50, 65, 80, 84, 96, 106, 123, 118, 134, 121};
double[] yvals2 = new double[]{35, 55, 40, 75, 65, 90, 106, 100, 130, 125, 144, 131};
XYSeries series = new XYSeries("2012 Sales Data");
for (int i = 0; i < 12; i++)
series.add(xvals[i], yvals[i]);
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setDisplayChartValues(true);
mDataset.addSeries(series);
mRenderer.addSeriesRenderer(renderer);
series = new XYSeries("2013 Sales Data");
for (int i = 0; i < 12; i++)
series.add(xvals[i], yvals2[i]);
renderer = new XYSeriesRenderer();
renderer.setColor(Color.GREEN);
renderer.setDisplayChartValues(true);
mDataset.addSeries(series);
mRenderer.addSeriesRenderer(renderer);
mRenderer.setChartTitle("Sales Chart Comparison 2012 - 2013");
mRenderer.setXTitle("Month");
mRenderer.setYTitle("Sales in 1000s");
mRenderer.setXAxisMin(0.5);
mRenderer.setXAxisMax(12.5);
mRenderer.setYAxisMin(20);
mRenderer.setYAxisMax(140);
mRenderer.setAxesColor(Color.GRAY);
mRenderer.setLabelsColor(Color.LTGRAY);
mRenderer.setXLabels(1);
mRenderer.setYLabels(10);
mRenderer.addXTextLabel(1, "Jan");
mRenderer.addXTextLabel(3, "Mar");
mRenderer.addXTextLabel(5, "May");
mRenderer.addXTextLabel(7, "Jul");
mRenderer.addXTextLabel(10, "Oct");
mRenderer.addXTextLabel(12, "Dec");
代码片段 12。 为样例应用 ++ 柱状图配置数据集和渲染器
如代码片段所示,我们可以分别创建和配置每个系列。 可以选择其他自定义设置,与前一部分中折线图类似。于折线图和柱状图均由属 XYChart的同一基本类型,二者存在很多相似之处。 对于此类图表,从某一类型转换至另一类型只需改变 ChartFactory的调用即可。
采用 ChartFactory类来获得 Android 视图的柱状图,上下文传递、数据系列和渲染器对象。
mChartView = ChartFactory.getBarChartView(context, mDataset, mRenderer, BarChart.Type.DEFAULT);
LinearLayout layout = (LinearLayout) findViewById(R.id.chart3);
layout.addView(mChartView);
代码片段 13。 在样例应用 ++ 中添加柱状图至 Android 布局中
最后,柱状图可以嵌入到如代码片段中所示的 chart3线性布局之中。
最终生成图表如下列屏幕截图所示。
![]()
图 5.采用柱状图进行销售比较
在一个活动中嵌入多个图表
借助 Android UI 布局技巧,我们能够添加多个 AChartEngine图表至同一个活动中,或者添加任何占位符位置至布局中。 下列代码片段展示了如何将上文探讨过的全部图表添加至一个活动布局之中。
<?xml version="1.0" encoding="utf-8"?><ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:fillViewport="true">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical"
android:weightSum="1"
android:gravity="center"
android:background="@android:color/transparent"><TextView
android:layout_width="261dp"
android:layout_height="104dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Menu Items Pie Chart"
android:gravity="center"
android:id="@+id/textView" /><LinearLayout
android:orientation="vertical"
android:layout_width="600dp"
android:layout_height="400dp"
android:id="@+id/chart1"
android:layout_gravity="center_horizontal"
android:background="@android:color/transparent"></LinearLayout><TextView
android:layout_width="268dp"
android:layout_height="104dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Sales Trend"
android:gravity="center"
android:id="@+id/textView2" /><LinearLayout
android:orientation="vertical"
android:layout_width="600dp"
android:layout_height="400dp"
android:id="@+id/chart2"
android:layout_gravity="center_horizontal"></LinearLayout><TextView
android:layout_width="344dp"
android:layout_height="122dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Sales Comparison Chart"
android:gravity="center"
android:id="@+id/textView3" /><LinearLayout
android:orientation="vertical"
android:layout_width="600dp"
android:layout_height="400dp"
android:id="@+id/chart3"
android:layout_gravity="center_horizontal"></LinearLayout></LinearLayout></ScrollView>
代码片段 14。 样例应用 ++ 中展示多个图表的布局
最终生成的视图如下列屏幕截图(纵向模式)所示。 滚动查看自动控制触控滚动导航。
![]()
图 6. 在 Android 活动中的多个嵌入式图表
总结
本文探讨了 Andorid 中可用的不同制图选项,并分别分析了每种途径的优势和劣势。 我们采用 Android 中最常用的图库之一 AChartEngine,采用一款饭店样例应用,展示了如何添加饼形图、折线图和柱状图。 并且讨论了不同的图表自定义和布局等相关问题。
关于作者
Ashok Emani 是英特尔软件及服务事业部的软件工程师。 他目前负责英特尔® 凌动™ 处理器大规模支持项目。
声明
本文件中包含关于英特尔产品的信息。 本文件不构成对任何知识产权的授权,包括明示的、暗示的,也无论是基于禁止反言的原则或其他。 除英特尔产品销售的条款和条件规定的责任外,英特尔不承担任何其他责任。英特尔在此作出免责声明:本文件不构成英特尔关于其产品的使用和/或销售的任何明示或暗示的保证,包括不就其产品的(i)对某一特定用途的适用性、(ii)适销性以及(iii)对任何专利、版权或其他知识产权的侵害的承担任何责任或作出任何担保。
除非经过英特尔的书面同意认可,英特尔的产品无意被设计用于或被用于以下应用:即在这样的应用中可因英特尔产品的故障而导致人身伤亡。
英特尔可以随时在不发通知的情况下修改规格和产品说明。 设计者不应信赖任何英特产品所不具有的特性,设计者亦不应信赖任何标有“保留权利”或“未定义”说明或特性描述。 对此,英特尔保留将来对其进行定义的权利,同时,英特尔不应为因其日后更改该等说明或特性描述而产生的冲突和不相容承担任何责任。 此处提供的信息可随时改变而毋需通知。 请勿根据本文件提供的信息完成一项产品设计。
本文件所描述的产品可能包含使其与宣称的规格不符的设计缺陷或失误。 英特尔提供最新的勘误表备索。
在发出订单之前,请联系当地的英特尔营业部或分销商以获取最新的产品规格。
索取本文件中或英特尔的其他材料中提的、包含订单号的文件的复印件,可拨打 1-800-548-4725,或登陆: http://www.intel.com/design/literature.htm
性能测试中使用的软件和工作负载可能仅在英特尔® 微处理器上针对性能进行了优化。 SYSmark* 和 MobileMark* 等性能测试均使用特定的计算机系统、组件、软件、操作和功能进行测量。 对这些因素的任何更改可能导致不同的结果。 请参考其他信息及性能测试(包括结合其他产品使用时的运行性能)以对您的目标产品采购进行全面评估。
对本文件中包含的软件源代码的提供均依据相关软件许可而做出,任何对该等源代码的使用和复制均应按照相关软件许可的条款执行。