Android使用AChartEngine製作動態心電圖效果

來源:互聯網
上載者:User

標籤:

AChartEngine是一個很強大的圖表引擎,我在上學的時候就接觸過,並且利用它做了一個感應器的應用,想想現在也很久遠了,今天就把這個app的源碼貼出來供其他人研究這款引擎。

app的效果如下:

github項目地址:https://github.com/AlexZhuo/SensorMonitor

此APP的主要特性如下:

1、支援手機感應器數量探測,支援加速度,磁場,距離等感應器資料的即時擷取

2、使用了一些github上的第三方控制項來美化UI,

3、支援全螢幕顯示

4、通過舊版的xUtils 2實現了資料庫即時記錄

5、通過POI來將資料庫的資料匯出為excel,方便以後分析。


AChartEngine根據事先準備好的資料進行繪圖,也就是說是一幀一幀的進行繪製,如果我們想動態產生波浪圖並讓座標軸隨之移動其實也不難,只需要隔一段時間在舊資料上添加資料並重新整理一下view即可。

想要在項目中使用這個表徵圖引擎,AChartEngine的jar包的:

http://repository-achartengine.forge.cloudbees.com/snapshot/org/achartengine/achartengine/1.2.0/

注意版本,以後說不定還會出新版。

下面把控制繪圖的代碼貼一下,原理其實不是很複雜,github上有全部app的代碼,如果你喜歡也可以在原來基礎上幫我完善一下(學生時代第一個上線項目,想想還有點小激動)。

import java.util.List;import org.achartengine.ChartFactory;import org.achartengine.GraphicalView;import org.achartengine.chart.PointStyle;import org.achartengine.model.XYMultipleSeriesDataset;import org.achartengine.model.XYSeries;import org.achartengine.renderer.XYMultipleSeriesRenderer;import org.achartengine.renderer.XYSeriesRenderer;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.graphics.Color;import android.graphics.Paint.Align;import android.hardware.Sensor;import android.hardware.SensorEvent;import android.hardware.SensorEventListener;import android.hardware.SensorManager;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.Vibrator;import android.view.ViewGroup.LayoutParams;import android.widget.LinearLayout;import android.widget.TextView;import com.lidroid.xutils.DbUtils;import com.lidroid.xutils.db.sqlite.Selector;import com.lidroid.xutils.exception.DbException;import com.situ.model.Accelerate_info;public class AccelActivity extends Activity{public SensorManager sensorManager;public Sensor accelSensor ;TextView xText ;TextView yText ;TextView zText ;TextView sumText;TextView danWei ;TextView title;private Vibrator vibrator;  SensorEventListener threeParamListener;SensorEventListener oneParamListener;SensorEventListener twoParamListener;Handler avgHandler;Thread avgThread;int sensor_id = 0;//圖表相關 private XYSeries series; private XYMultipleSeriesDataset mDataset; private GraphicalView chart; private XYMultipleSeriesRenderer renderer; private Context context; private int yMax = 20;//y軸最大值,根據不同感應器變化 private int xMax = 100;//一屏顯示測量次數@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_accel);sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);avgHandler = new AveHandler();//給控制項執行個體化if(xText==null){findViews();}Intent intent = getIntent();avgThread = new Thread(runnable);//定期更新平均值的線程啟動avgThread.start();//初始化各個監聽器                initListeners();       switch (wtd) {case Sensor.TYPE_ACCELEROMETER:title.setText("加速度感應器");danWei.setText("N/M^2");accelSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);sensorManager.registerListener(threeParamListener, accelSensor, sensorManager.SENSOR_DELAY_UI);yMax = 20;sensor_id = 1;break;default:break;}        //初始化圖表        initChart("*0.5s", danWei.getText().toString(),0,xMax,0,yMax);}/** * 抓取view中文本控制項的函數 */private void findViews(){xText = (TextView) findViewById(R.id.xAxis);yText = (TextView) findViewById(R.id.yAxis);zText = (TextView) findViewById(R.id.zAxis);sumText = (TextView) findViewById(R.id.sum);danWei = (TextView) findViewById(R.id.danWei);title = (TextView) findViewById(R.id.title);}/** * 初始化各類監聽器 */private void initListeners() {threeParamListener = new SensorEventListener() {//有三個返回參數的監聽器@Overridepublic void onSensorChanged(SensorEvent event) {// TODO Auto-generated method stubxText.setText(event.values[0]+""); yText.setText(event.values[1]+""); zText.setText(event.values[2]+""); double sum = threeDimenToOne(event.values[0], event.values[1], event.values[2]);giveAverage(sum);//將當前測量的結果寫入buffer,然後定期求buffer裡面的平均值,並顯示}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// TODO Auto-generated method stub}};}/** * 初始化圖表 */private void initChart(String xTitle,String yTitle,int minX,int maxX,int minY,int maxY){//這裡獲得main介面上的布局,下面會把圖表畫在這個布局裡面        LinearLayout layout = (LinearLayout)findViewById(R.id.chart);        //這個類用來放置曲線上的所有點,是一個點的集合,根據這些點畫出曲線        series = new XYSeries("曆史曲線");        //建立一個資料集的執行個體,這個資料集將被用來建立圖表        mDataset = new XYMultipleSeriesDataset();        //將點集添加到這個資料集中        mDataset.addSeries(series);                //以下都是曲線的樣式和屬性等等的設定,renderer相當於一個用來給圖表做渲染的控制代碼        int lineColor = Color.BLACK;        PointStyle style = PointStyle.CIRCLE;        renderer = buildRenderer(lineColor, style, true);              //設定好圖表的樣式        setChartSettings(renderer, xTitle,yTitle,         minX, maxX, //x軸最小最大值        minY, maxY, //y軸最小最大值        Color.BLACK, //座標軸顏色        Color.WHITE//標籤顏色        );               //組建圖表        chart = ChartFactory.getLineChartView(this, mDataset, renderer);                //將圖表添加到布局中去        layout.addView(chart, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();if(threeParamListener!=null){sensorManager.unregisterListener(threeParamListener);}if(oneParamListener!=null){sensorManager.unregisterListener(oneParamListener);}if(avgThread!=null)avgThread.interrupt();DbUtils db = DbUtils.create(getApplicationContext());//xUtils架構try {List<Accelerate_info> list = db.findAll(Selector.from(Accelerate_info.class).where("sensor", "=", sensor_id));//看看一共寫入了資料庫多少資料System.out.println("數量是"+list.size());} catch (DbException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/** * 根據三個座標向量求和向量的模 * @param x * @param y * @param z * @return */public static double threeDimenToOne(double x,double y,double z){return Math.sqrt(x*x+y*y+z*z);}public  int index = 0;//指示這段時間一共寫入了多少個資料//在這裡可以設定緩衝區的長度,用於求平均數double[] buffer = new double[500];//半秒鐘最多放500個數public int INTERVAL = 500;//每半秒求一次平均值 public double AVERAGE = 0;//儲存平均值/** * 一個子線程,沒隔固定時間計算這段時間的平均值,並給textView賦值 */Runnable runnable = new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println("線程已經啟動");while(true){try {Thread.sleep(INTERVAL);//沒隔固定時間求平均數} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();avgThread = new Thread(runnable);avgThread.start();}if(index!=0){double sum = 0;for (int i=0;i<index;i++) {sum+=buffer[i];}AVERAGE = sum/new Double(index);index=0;//讓下標恢複}avgHandler.sendEmptyMessage(1);//提示handler更新ui}}};/** * 更新平均值的顯示值 */public void setAverageView(){//更新textViewif(sumText==null)return;sumText.setText(AVERAGE+"");}/** * 每隔固定時間給平均值賦值,並且更新圖表的操作 * @author love fang * */class AveHandler extends Handler{@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsetAverageView();//顯示平均值updateChart();//更新圖表//把當前值存入資料庫DbUtils db = DbUtils.create(getApplicationContext());Accelerate_info accelerate_info = new Accelerate_info(System.currentTimeMillis(), AVERAGE, sensor_id); try {db.save(accelerate_info);//將當前平均值存入資料庫} catch (DbException e) {// TODO Auto-generated catch blocke.printStackTrace();System.out.println("儲存失敗");}}}/** * 接受當前感應器的測量值,存到緩衝區中去,並將下標加一 * @param data */public void giveAverage(double data){buffer[index]=data;index++;}/**         *設定圖表曲線樣式         **/             protected XYMultipleSeriesRenderer buildRenderer(int color, PointStyle style, boolean fill) {     XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();         //設定圖表中曲線本身的樣式,包括顏色、點的大小以及線的粗細等     XYSeriesRenderer r = new XYSeriesRenderer();     r.setColor(color);     r.setPointStyle(style);     r.setFillPoints(fill);     r.setLineWidth(2);//這是線寬     renderer.addSeriesRenderer(r);         return renderer;    }/** * 初始化圖表 * @param renderer * @param xTitle * @param yTitle * @param xMin * @param xMax * @param yMin * @param yMax * @param axesColor * @param labelsColor */  protected void setChartSettings(XYMultipleSeriesRenderer renderer, String xTitle, String yTitle,    double xMin, double xMax, double yMin, double yMax, int axesColor, int labelsColor) {     //有關對圖表的渲染可參看api文檔     renderer.setChartTitle(title.getText().toString());//設定標題     renderer.setXAxisMin(xMin);//設定x軸的起始點     renderer.setXAxisMax(xMax);//設定一屏有多少個點     renderer.setYAxisMin(yMin);     renderer.setYAxisMax(yMax);     renderer.setBackgroundColor(Color.BLACK);     renderer.setLabelsColor(Color.YELLOW);     renderer.setAxesColor(axesColor);     renderer.setLabelsColor(labelsColor);     renderer.setShowGrid(true);     renderer.setGridColor(Color.BLUE);//設定格子的顏色     renderer.setXLabels(20);//沒有什麼卵用     renderer.setYLabels(20);//把y軸刻度平均分成多少個     renderer.setXTitle(xTitle);//x軸的標題     renderer.setYTitle(yTitle);//y軸的標題     renderer.setYLabelsAlign(Align.RIGHT);     renderer.setPointSize((float) 2);     renderer.setShowLegend(false);    }    int[] xv = new int[1000];//用來顯示的資料  double[] yv = new double[1000];  private int addX = -1;  private double addY = 0;  /**   * 更新圖表的函數,其實就是重繪   */    private void updateChart() {               //設定好下一個需要增加的節點               addY = AVERAGE;//需要增加的值        //移除資料集中舊的點集        mDataset.removeSeries(series);        //判斷當前點集中到底有多少點,因為螢幕總共只能容納100個,所以當點數超過100時,長度永遠是100                         //每一個新點座標都後移一位     series.add(addX++, addY);//最重要的一句話,以xy對的方式往裡放值          if(addX>100){//如果超出了螢幕邊界,實現座標軸自動移動的方法     renderer.setXAxisMin(addX-100);//顯示範圍為100     renderer.setXAxisMax(addX);     }               //重要:在資料集中添加新的點集     mDataset.addSeries(series);          //視圖更新,沒有這一步,曲線不會呈現動態     //如果在非UI主線程中,需要調用postInvalidate(),具體參考api     chart.invalidate();    }}



Android使用AChartEngine製作動態心電圖效果

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.