使用AChartEngine画图,项目总结

再来博客园上冒个泡~
从07-24~07-31做了一个把数据在android手机上进行图形化显示的工作。总结一下项目过程中的收获与问题。
 
 
设计了两个界面,第一个主界面用来显示不同的数据处理类型,第二个数据显示界面用来显示数据处理得到的结果 
主界面如左图所示,对采集自肌肉电信号传感器的数据进行处理,不同的处理方法可以反映肌肉的一些指标(肌肉力量(肌群肌力)/肌肉活性(肌群活性)/肌肉疲劳度(肌群疲劳度))
数据显示界面如右图所示,把数据用条形图显示出来,四个条形图分别代表了不同肌肉采样位置的结果。
MainActivity       
 
作为一个刚刚开始学习java和android的新手,感觉项目中主要的难点或者自己一直在忙于解决的问题有:
 
1.    在主界面中显示三个 可供选择的 条型框, 用到了ListActivity的最基本的内容。
2.    在点击条型框之后,如何开启一个新的界面并且在新的界面(Activity)中可以获得从主界面传过来的信息,用到了intent.startActivity
3.    用AChartEngine画图,画图本身并不难,难点在于如何动态刷新条形图,使得条形图里的数据能反映当前最近一段时间内的效果。
        解决方法是开启一个新的线程,在新线程里定时 对UI进行刷新。
4.    使用android的sqlite进行数据库存储时,如何存储数组。 解决方案是把数组转换成Byte[]的形式在sqlite里面用block的方式进行存储。
 
对肌肉电信号的数据处理方法就不讲了,涉及到公司产权而且也与android开发没有关系。
 
下面的内容是分别总结一下在解决问题的过程中遇到的收获。

1.    ListActivity显示三个可供选择的条型框。

 
public class MainActivity extends ListActivity 
在onCreat方法中, 使用
1  SimpleAdapter adapter= new SimpleAdapter( this , maps ,
2         android.R.layout. simple_list_item_2 , // SDK 库中提供的一个包含两个 TextView 的 layout
3         new String[]{ "name" , "desc" }, // maps 中的两个 key
4         new int []{android.R.id. text1 ,android.R.id. text2 } // 两个 TextView 的 id      
5         );
6         this .setListAdapter(adapter);
就可以把maps中包含的数据按照listview默认的方式进行显示了。在android的reference里面对simpleAdapter的描述如下所示:
        An easy adapter to map static data to views defined in an XML file. You can specify the data backing the list as an ArrayList of Maps. 
Each entry in the ArrayList corresponds to one row in the list. The Maps contain the data for each row.
    简单来说就是maps中的每一项数据对应着表格中的每一行。maps的数据类型是:ArrayList<Map<String,String>>,可以存放HashMap数据。
 
    this.setListAdapter则可以把adapter的指针传给ListActivity。
 

2.    在点击条型框之后,如何开启一个新的界面并且在新的界面(Activity)中可以获得从主界面传过来的信息

    
    界面与界面的传递,即从A activity到 B activity的传递,可以使用intent来完成,如下所示。
    把数据按照key-value的形式封装在bundle里面,使用intent.putExtra(bundle)可以把数据传入到新的activity之中,
    使用Bundle extras = getIntent().getExtras() 的方式即可获得bundle。
1               Intent intent=new Intent();  
2               
3               Bundle b = new Bundle();   
4               b.putString("DataKind", ""+id);  
5               //此处使用putExtras,接受方就响应的使用getExtra  
6               intent.putExtras( b );    
7  
8               intent.setClass(MainActivity.this,TestActivity.class);  
9               startActivity(intent);
 

3.    用AChartEngine画图,并把条形图动态显示。

    
    AChartEngine是一款开源的/免费的在android上进行画图的软件包,
官网上https://code.google.com/p/achartengine/可以下载对应的jar包,在工程里add external archives就可以使用到里面工具类和库函数了。
只是把AChartEngine当作一种工具在用,所以并没有系统的了解AChartEngine的原理和框架结构,直接参考了AChartEngine官网里的例子TempertureDemo就做出了
数据显示界面里的条形图。使用起来很是方便
1 GraphicalView getChartView  =  ChartFactory.getBarChartView( 
2                             context , mDataSet, renderer, Type.DEFAULT );
 
其中,
    mDataSet是要显示的数据集合,把数据放到Series series中,通过 mDataSet.addSeries(series.toXYSeries());即可;
    render是渲染器,可以设置图表的一些属性,比如显示个数/显示范围/显示颜色等。
    调用ChartFactory中不同的函数可以获得不同的图表类型,这里getBarChartView获得的是条形图。
有不少的例子可以学习,
 
    至于动态更新图表的问题的解决方案,在互联网上搜了一圈,也没有找到比较可靠的成熟的处理方法,只能在handler中更新UI的方式来实现。
    具体说来就是每隔一段时间(这里的更新时间是500ms),在handler里面删除旧的view,更新mDataSet里面的数据后用ChartFactory得到新的
view,放在原来的位置上,形成动态效果(view每500ms更新一次,其实是view每500ms替换一次。)
    这里面有两个问题需要说清楚,第一个是为什么要在handler里面更新UI,第二个是线程与进程。
    这里可以补充一些进程与线程的基础知识。
    一个安卓app独占一个进程,一个进程中可以有多个线程(thread),实际处理问题的是线程。
    进程中的main thread 是 UI thread , 其主要的功能是负责UI界面的显示/更新和空间交互。
    为了保证界面的流畅性,费时的工作应该放在其他线程中去执行,如果需要更新UI,则通过handler来告知主线程,在且只能在主线程的handler message中去执行更新
UI的操作。
    handler的作用:把消息加入特定的消息队列中,并分发和处理消息队列中的消息。构造handler时可以指定一个looper对象,默认为当前线程的looper构建。
                               调用handler 的sendmessage接口,就会把消息放入到消息队列中。               
    在activity中建立handler不需要looper,因为activity有自己的looper,但在新的线程中建立handler时,则需要使用下面的方法:
1      Looper.prepare(); 
2       myThreadHandler = new Handler() {
3              public void handleMessage(android.os.Message msg) {
4               }
5        };
6        Looper.myLooper().loop();//建立一个消息循环,该线程不会退出
    实现动态更新UI的过程如下所示:
 
(注:使用dispatchMessage的原因:如果Message对象自带callback对象,dispatchMessage执行的就是msg的callback中对应的run方法,而handler.post(runnable r)就是把r添加到msg.callback中去)
 
 

4.    android的sqlite进行数据库存储时,存储数组的小技巧。

    
    在sqlite存储数据时,有5中数据类型可以用到
1.NULL:空值。
2.INTEGER:带符号的整型,具体取决有存入数字的范围大小。
3.REAL:浮点数字,存储为8-byte IEEE浮点数。
4.TEXT:字符串文本。
5.BLOB:二进制对象。
    没有数组的存放方法。通过在网上进行搜索,查到了一种,把数组转成二进制的serializeObject,用BLOB的方式进行存储。
    序列化和反序列化的方法如下:
 1 public static byte[] serializeObject(Object o) { 
 2     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
 3  
 4     try { 
 5       ObjectOutput out = new ObjectOutputStream(bos); 
 6       out.writeObject(o); 
 7       out.close(); 
 8  
 9       // Get the bytes of the serialized object 
10       byte[] buf = bos.toByteArray(); 
11  
12       return buf; 
13     } catch(IOException ioe) { 
14       Log.e("serializeObject", "error", ioe); 
15  
16       return null;
17     } 
18 }
19  
20  
21 public static Object deserializeObject(byte[] b) { 
22     try { 
23       ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(b)); 
24       Object object = in.readObject(); 
25       in.close(); 
26  
27       return object; 
28     } catch(ClassNotFoundException cnfe) { 
29       Log.e("deserializeObject", "class not found error", cnfe); 
30  
31       return null; 
32     } catch(IOException ioe) { 
33       Log.e("deserializeObject", "io error", ioe); 
34  
35       return null;
36   } 
37 }

 

 
    serializeObject对list类型的数据可以有规律的存储,从而在deserializeObject中有规律的解出来。
使用方法如下:
1  
2         byte[] dByte = serializeObject(listDArray);
3         SerializedListData = (List<List<Double>> ) deserializeObject(dByte);
    其中,listDArray和SerializedListData都是List<List<Double>>类型的数据。
 
  总结起来好水~~一个星期只做了这么点工作,不过也算学到了一些知识。
  第一篇实习总结文章,有不对或者不清楚的地方欢迎留下评论~

posted on 2013-08-02 16:07  Leo Han  阅读(1572)  评论(0编辑  收藏  举报