最近公司项目需要用到瀑布流的条形图和饼状图,于是自己在网上百度了下Google的开源achartengine,里边的东西非常全面, 支持多种图标,如折线图、气泡图、饼状图等等,闲来之余,自己想研究一下它的底层是如何实现的,发现还是比较深的,由于我的水平有限,只能看到一些皮毛,拿出来分享一下,如有不正确的地方,欢迎大家指教,谢谢!
1:看一下 ChartActivity,它的源码和界面如下:
public class ChartActivity extends ListActivity {
private IDemoChart[] mCharts = new IDemoChart[] {
new AverageTemperatureChart(), new AverageCubicTemperatureC hart(),
new SalesStackedBarChart(), new SalesBarChart(),
new TrigonometricFunctionsCh art(), new ScatterChart(),
new SalesComparisonChart(), new ProjectStatusChart(),
new SalesGrowthChart(), new BudgetPieChart(),
new BudgetDoughnutChart(), new ProjectStatusBubbleChart (),
new TemperatureChart(), new WeightDialChart(),
new SensorValuesChart(), new CombinedTemperatureChart (),
new MultipleTemperatureChart () };

private String[] mMenuText;

private String[] mMenuSummary;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int length = mCharts.length;
mMenuText = new String[length + 3];
mMenuSummary = new String[length + 3];
mMenuText[0] = "Embedded line chart demo";
mMenuSummary[0] = "A demo on how to include a clickable line chart into a graphical activity";
mMenuText[1] = "Embedded pie chart demo";
mMenuSummary[1] = "A demo on how to include a clickable pie chart into a graphical activity";
for (int i = 0; i < length; i++) {
mMenuText[i + 2] = mCharts[i].getName();
mMenuSummary[i + 2] = mCharts[i].getDesc();
}
mMenuText[length + 2] = "Random values charts";
mMenuSummary[length + 2] = "Chart demos using randomly generated values";
setListAdapter(new SimpleAdapter(this, getListValues(),
android.R.layout.simple_list_item_2, new String[] {
IDemoChart.NAME, IDemoChart.DESC }, new int[] {
android.R.id.text1, android.R.id.text2 }));
}

private List > getListValues() {
List > values = new ArrayList >();
int length = mMenuText.length;
for (int i = 0; i < length; i++) {
Map v = new HashMap();
v.put(IDemoChart.NAME, mMenuText[i]);
v.put(IDemoChart.DESC, mMenuSummary[i]);
values.add(v);
}
return values;
}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent intent = null;
if (position == 0) {
intent = new Intent(this, XYChartBuilder.class);
} else if (position == 1) {
intent = new Intent(this, PieChartBuilder.class);
} else if (position <= mCharts.length + 1) {
intent = mCharts[position - 2].execute(this);
} else {
intent = new Intent(this, GeneratedChartDemo.class);
}
startActivity(intent);
}
}

Google开源图标库之achartengine源码分析--第一节


其中IDemoChart[] mCharts是一个元素为IDemoChart的数组,每一个IDemoChart的实体类有自己的名字和说明,分别为getName方法和getDesc方法,这也就是ListActivity中显示出来的文字了
2:当我们点击某一个IDemoChart,会相应执行ListActivity的onListItemClick方法,此方法会对position的位置进行判断,生成相应的intent对象,然后执行startActivity的方法,重点就在这里了,这个intent对象是如何生成的呢?
3:比如,我们点击的是BudgetDoughnutChart,在onListItemClick方法中会调用BudgetDoughnutChart的execute(Context context)方法,如下是execute(Context context)方法源码

public Intent execute(Context context) {
List values = new ArrayList();
values.add(new double[] { 12, 14, 11, 10, 19 });
values.add(new double[] { 10, 9, 14, 20, 11 });
List titles = new ArrayList();
titles.add(new String[] { "P1", "P2", "P3", "P4", "P5" });
titles.add(new String[] { "Project1", "Project2", "Project3",
"Project4", "Project5" });
int[] colors = new int[] { Color.BLUE, Color.GREEN, Color.MAGENTA,
Color.YELLOW, Color.CYAN };

DefaultRenderer renderer = buildCategoryRenderer(colors);
renderer.setApplyBackgroundColor(true);
renderer.setBackgroundColor(Color.rgb(222, 222, 200));
renderer.setLabelsColor(Color.GRAY);
return ChartFactory.getDoughnutChartIntent(context,
buildMultipleCategoryDat aset("Project budget", titles, values),
renderer, "Doughnut chart demo");
}
Google开源图标库之achartengine源码分析--第一节

第一次看了之后,有点奇怪哦,跟我们普通的startActivity方法完全不一样,根本没有class参数,那应该往哪里跳转呢?许多朋友看到这里,应该都奇怪了,为了能清楚它的底层实现,我们必须要对jar包反编译,才能看到。

Google开源图标库之achartengine源码分析--第一节


4:用jd-gui工具对achartengine-1.1.0.jar包进行反编译,我们可以得到整个执行的类图如下:
Google开源图标库之achartengine源码分析--第一节

5:我们可以从ChartFactory类来看,它的getDoughnutChartIntent方法如下:
   public static final Intent getDoughnutChartIntent(Context context, MultipleCategorySeries dataset, DefaultRenderer renderer, String activityTitle)
   {
      checkParameters(dataset, renderer);
      Intent intent = new Intent(context, GraphicalActivity.class);
      DoughnutChart chart = new DoughnutChart(dataset, renderer);
      intent.putExtra("chart", chart);
      intent.putExtra("title", activityTitle);
      return intent;
   }
看到这里就明白了,原来Google自己新建了一个GraphicalActivity,用来显示画出来的图表,这样就可以正常执行startActivity(intent)方法了,那最终的view是在哪里画出来的呢?我们继续往下看。

6:在GraphicalActivity中非常简单,就是构建了一个View对象,然后把它显示出来就可以了,最终界面上显示的就是一个GraphicalView,源码如下:
Bundle extras = getIntent().getExtras();
      this.mChart = ((AbstractChart)extras.getSerializable("chart"));
      this.mView = new GraphicalView(this, this.mChart);

7:到这里我们一定要清楚,显示这个view需要作的有三件事,第一,两个圈显示的颜色从哪里来;第二,外圈每种颜色都对应一个名称;第三,内圈每种颜色都对应一个名称,这些数据从哪里来呢?
再回来BudgetDoughnutChart类中,execute方法执行中有:DefaultRenderer renderer = buildCategoryRenderer(colors);//渲染器代码,它就是生成渲染器,可以看一下传给它的参数为int[] colors = new int[] { Color.BLUE, Color.GREEN, Color.MAGENTA,
Color.YELLOW, Color.CYAN },里边的五种颜色就是最后显示出来的;
然后就是buildMultipleCategoryDat aset("Project budget", titles, values)方法,它的返回值为MultipleCategorySeries,Multiple为多元的意思,Category为分类,Series为系列,综合就是一个分类管理器,它是回调的AbstractDemoChart类的buildMultipleCategoryDat aset方法,源码如下:

protected MultipleCategorySeries buildMultipleCategoryDat aset(String title,
List titles, List values) {
MultipleCategorySeries series = new MultipleCategorySeries(title);
int k = 0;
for (double[] value : values) {
series.add(2007 + k + "", titles.get(k), value);
k++;
}
return series;
}

我们可以看一下传给它的参数,titles和values,就是显示的文字信息,看到这里就应该明白一些了,我们继续往下看。
values.add(new double[] { 12, 14, 11, 10, 19 });
values.add(new double[] { 10, 9, 14, 20, 11 });
List titles = new ArrayList();
titles.add(new String[] { "P1", "P2", "P3", "P4", "P5" });
titles.add(new String[] { "Project1", "Project2", "Project3",
"Project4", "Project5" });

8:拿到我们需要的所有数据后,最终在GraphicalView类中生成我们需要显示的View,其中的mTouchHandler即为我们滑动时,执行滑动的监听,如果大家不需要滑动的话,可以设置相应的滑动监听
public GraphicalView(Context context, AbstractChart chart)
   {
      super(context);
      this.mChart = chart;
      this.mHandler = new Handler();
      if (this.mChart instanceof XYChart)
         this.mRenderer = ((XYChart)this.mChart).getRenderer();
      else {
         this.mRenderer = ((RoundChart)this.mChart).getRenderer();
      }
      if (this.mRenderer.isZoomButtonsVisible()) {
         this.zoomInImage = BitmapFactory.decodeStream(GraphicalView.class.getResourceAsStream("image/zoom_in.png"));

         this.zoomOutImage = BitmapFactory.decodeStream(GraphicalView.class.getResourceAsStream("image/zoom_out.png"));

         this.fitZoomImage = BitmapFactory.decodeStream(GraphicalView.class.getResourceAsStream("image/zoom-1.png"));
      }

      if ((this.mRenderer instanceof XYMultipleSeriesRenderer ) && (((XYMultipleSeriesRenderer )this.mRenderer).getMarginsColor() == 0))
      {
         ((XYMultipleSeriesRenderer )this.mRenderer).setMarginsColor(this.mPaint.getColor());
      }
      if (((this.mRenderer.isZoomEnabled()) && (this.mRenderer.isZoomButtonsVisible())) || (this.mRenderer.isExternalZoomEnabled()))
      {
         this.mZoomIn = new Zoom(this.mChart, true, this.mRenderer.getZoomRate());
         this.mZoomOut = new Zoom(this.mChart, false, this.mRenderer.getZoomRate());
         this.mFitZoom = new FitZoom(this.mChart);
      }
      int version = 7;
      try {
         version = Integer.valueOf(Build.VERSION.SDK).intValue();
      }
      catch (Exception e) {
      }
      if (version < 7)
         this.mTouchHandler = new TouchHandlerOld(this, this.mChart);
      else
         this.mTouchHandler = new TouchHandler(this, this.mChart);
   }
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐