網站首頁 編程語言 正文
我們在安卓開發中,有時會用到統計圖表的功能,而曲線繪制是其中比較典型的一種,一般是利用給定的坐標點集和安卓自帶的繪圖模塊進行繪制,直接得到的是一張完整的靜態的曲線圖。但有時,我們需要動態繪制一些曲線圖,就像我們打開電腦的任務管理器,里面有一個CPU使用記錄的動態變化的帶網格的曲線圖,對于這一類的曲線繪制,安卓SDK自帶的繪圖模塊貌似就不那么好用了。
在這里,我就利用Handler+timer機制和第三方開發包achartengine實現動態繪制安卓手機充放電曲線的應用。
1、下載第三方開發包achartengine,也就是jar包,可以在網上找到下載源,我下載的是achartengine-1.1.0.jar;
2、在創建的應用工程文件中引入該jar包,以Eclipse為例方法是:在包資源管理器目錄中右鍵單擊已創建的項目名稱——>構建路徑——>配置構建路徑——>Java構建路徑——>庫——>外部JAR,然后找到achartengine包的存放路徑,找到achartengine-1.1.0.jar文件,點擊打開即完成了該包的引用,這時會在項目目錄下出現一個名為引用的庫文件,里面就是我們剛才引入的jar包。
3、接下來就可以按正常步驟開發該應用了,需要注意的是:需要在主類中引入jar中繪圖需要的庫文件,如下:
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;
同時需要在AndroidManifest.xml文件中加上語句: ? ? ? ? ? ??
<application ? ?android:icon="@drawable/ic_launcher" ? ?android:label="@string/app_name" > <activity android:name="org.achartengine.GraphicalActivity" />
4、接下來需要定義一些繪圖的變量和樣式: ? ? ? ? ? ??
private XYSeries series;
? ? ? ? ? ? ? private XYMultipleSeriesDataset mDataset;
? ? ? ? ? ? ? private GraphicalView chart;
? ? ? ? ? ? ? private XYMultipleSeriesRenderer renderer;
? ? ? ? ? ? ? private Context context, context1;
? ? ? ? ? ? ? private int addX = -1, addY;
? ? ? ? ? ? ? int[] xv = new int[720];// X軸數組元素個數
? ? ? ? ? ? ? int[] yv = new int[720];// Y軸數組元素個數 ? ? ? ??
? ? ? ? ? ? ? ? ? context = getApplicationContext();
? ? ? ? ? ? ? // 這里獲得main界面上的布局,下面會把圖表畫在這個布局里面
? ? ? ? ? ? ? LinearLayout layout = (LinearLayout) findViewById(R.id.linearLayout1);
? ? ? ? ? ? ? // 這個類用來放置曲線上的所有點,是一個點的集合,根據這些點畫出曲線
? ? ? ? ? ? ? series = new XYSeries(title);
? ? ? ? ? ? ? // 創建一個數據集的實例,這個數據集將被用來創建圖表
? ? ? ? ? ? ? mDataset = new XYMultipleSeriesDataset();
? ? ? ? ? ? ? // 將點集添加到這個數據集中
? ? ? ? ? ? ? mDataset.addSeries(series);
? ? ? ? ? ? ? // 以下都是曲線的樣式和屬性等等的設置,renderer相當于一個用來給圖表做渲染的句柄
? ? ? ? ? ? ? int color = Color.GREEN;
? ? ? ? ? ? ? PointStyle style = PointStyle.CIRCLE;
? ? ? ? ? ? ? renderer = buildRenderer(color, style, true);
?
? ? ? ? ? ? ? // 設置好圖表的樣式(橫軸時間分鐘值,縱軸電壓毫伏值)
? ? ? ? ? ? ? setChartSettings(renderer, "X", "Y", 0, 240, 3400, 4400, Color.WHITE,Color.WHITE);
? ? ? ? ? ? ? // 生成圖表
? ? ? ? ? ? ? chart = ChartFactory.getLineChartView(context, mDataset, renderer);
? ? ? ? ? ? ? // 將圖表添加到布局中去
? ? ? ? ? ? ? layout.addView(chart, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
?
? ? ? ? ? ? ? ?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((float) 1);// 線粗尺寸
? ? ? ? ? ? ? renderer.addSeriesRenderer(r);
? ? ? ? ? ? ? return renderer;
}
?
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);
renderer.setXTitle(xTitle);
renderer.setYTitle(yTitle);
renderer.setXAxisMin(xMin);
renderer.setXAxisMax(xMax);
renderer.setYAxisMin(yMin);
renderer.setYAxisMax(yMax);
renderer.setAxesColor(axesColor);
renderer.setLabelsColor(labelsColor);
renderer.setShowGrid(true);
renderer.setGridColor(Color.GREEN);// 曲線顏色
renderer.setXLabels(20);
renderer.setYLabels(10);
renderer.setChartTitle("時間/電壓變化曲線圖");// 圖表名稱
renderer.setXTitle("時間(min)");// 橫坐標名稱
renderer.setYTitle("電壓(mv)");// 縱坐標名稱
renderer.setYLabelsAlign(Align.RIGHT);
renderer.setPointSize((float) 1.5);// 設置點的大小
renderer.setShowLegend(false);
renderer.setPanEnabled(true, false);// 設置滑動,這邊是橫向可以滑動,縱向不可滑動
renderer.setZoomEnabled(true, false);// 設置縮放,橫向可以,縱向不可以
// renderer.setZoomLimits(new double[] { 0, 720, 3400, 4400 });//設置縮放的范圍
// renderer.setPanLimits(new double[] { -0.5, 720, 3400, 4400
// });//設置拉動的范圍
}
5、動態繪制的實現:動態繪制主要需要實現兩方面的內容,一是更新繪圖的方法、二是動態繪圖時間任務的定義。
1)更新繪圖方法: ? ? ? ? ? ??
private void updateChart()// 更新繪圖方法</strong>
{
// 設置好下一個需要增加的節點
addX = (int) (addX + 1);
addY = BatteryV;
// 移除數據集中舊的點集
mDataset.removeSeries(series);
// 判斷當前點集中到底有多少點,因為屏幕總共只能容納240個,所以當點數超過240時,長度永遠是240
int length = series.getItemCount();
if (length > 720) {
length = 720;
}
// 將舊的點集中x和y的數值取出來放入backup中,并且將x的值加1,造成曲線向右平移的效果
for (int i = 0; i < length; i++) {
xv[i] = (int) series.getX(i);
yv[i] = (int) series.getY(i);
}
// 點集先清空,為了做成新的點集而準備
series.clear();
// 將新產生的點首先加入到點集中,然后在循環體中將坐標變換后的一系列點都重新加入到點集中
// 這里可以試驗一下把順序顛倒過來是什么效果,即先運行循環體,再添加新產生的點
series.add(addX, addY);
for (int k = 0; k < length; k++) {
series.add(xv[k], yv[k]);
}
// 在數據集中添加新的點集
mDataset.addSeries(series);
// 視圖更新,沒有這一步,曲線不會呈現動態
// 如果在非UI主線程中,需要調用postInvalidate(),具體參考api
chart.invalidate();
}
2)時間任務定義: ? ? ? ? ? ? ?
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 刷新圖表
updateChart();// 電壓變化曲線刷新
updateChart1();// 電量變化曲線刷新
super.handleMessage(msg);
}
};
task = new TimerTask()// 刷新繪圖計時任務配置
{
@Override
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
timer.schedule(task, 0, 60000);// 以一分鐘為時間間隔運行?
再發一下完整的代碼:
主類:
package com.cfzz.vcd;
?
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
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 com.cfzz.vqcd.R;
?
//import com.cfzz.wy.R;
?
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint.Align;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.view.View.OnClickListener;
?
public class VoltageChangeDraw extends Activity {
?
?? ?// protected static final Activity Activity = null;
?? ?private PowerManager.WakeLock wl;
?? ?private Timer timer = new Timer();
?? ?private long mExitTime = 0;
?? ?private TimerTask task, task1;
?? ?private Handler handler;
?? ?private String title = "Signal Strength";
?? ?private XYSeries series, series1;
?? ?private XYMultipleSeriesDataset mDataset, mDataset1;
?? ?private GraphicalView chart, chart1;
?? ?private XYMultipleSeriesRenderer renderer, renderer1;
?? ?private Context context, context1;
?? ?private int addX = -1, addY;
?? ?private int addX1 = -1, addY1;
?? ?private Button button;
?? ?int[] xv = new int[720];// X軸數組元素個數
?? ?int[] yv = new int[720];// Y軸數組元素個數
?? ?int[] xv1 = new int[720];// X軸數組元素個數
?? ?int[] yv1 = new int[720];// Y軸數組元素個數
?? ?public TextView TV;
?? ?// ScreenShot screenShot = new ScreenShot();
?? ?private int BatteryN; // 目前電量
?? ?private int BatteryV; // 電池電壓
?? ?// private double BatteryT; //電池溫度
?? ?private String BatteryStatus; // 電池狀態
?? ?private String BatteryTemp; // 電池使用情況
?
?? ?/** Called when the activity is first created. */
?? ?@Override
?? ?public void onCreate(Bundle savedInstanceState) {
?? ??? ?super.onCreate(savedInstanceState);
?? ??? ?getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
?? ??? ??? ??? ?WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
?? ??? ?setContentView(R.layout.main);
?? ??? ?this.button = (Button) this.findViewById(R.id.my_button);// 截圖按鍵定義
?? ??? ?// 截圖按鍵監聽
?? ??? ?this.button.setOnClickListener(new OnClickListener() {
?? ??? ??? ?public void onClick(View v) {
?? ??? ??? ??? ?SimpleDateFormat sdf = new SimpleDateFormat(
?? ??? ??? ??? ??? ??? ?"yyyy-MM-dd_HH-mm-ss", Locale.US);// 日期格式名定義
?
?? ??? ??? ??? ?String fname = "/sdcard/" + sdf.format(new Date()) + ".png";// 存儲路徑及文件名定義
?
?? ??? ??? ??? ?View view = v.getRootView();
?
?? ??? ??? ??? ?view.setDrawingCacheEnabled(true);
?
?? ??? ??? ??? ?view.buildDrawingCache();
?
?? ??? ??? ??? ?Bitmap bitmap = view.getDrawingCache();
?
?? ??? ??? ??? ?if (bitmap != null) {
?? ??? ??? ??? ??? ?System.out.println("bitmap got!");
?
?? ??? ??? ??? ??? ?try {
?
?? ??? ??? ??? ??? ??? ?FileOutputStream out = new FileOutputStream(fname);
?
?? ??? ??? ??? ??? ??? ?bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);// 圖片格式及質量輸出
?
?? ??? ??? ??? ??? ??? ?System.out.println("file" + fname + "output done.");
?
?? ??? ??? ??? ??? ?} catch (Exception e) {
?
?? ??? ??? ??? ??? ??? ?e.printStackTrace();
?
?? ??? ??? ??? ??? ?}
?
?? ??? ??? ??? ?} else {
?? ??? ??? ??? ??? ?System.out.println("bitmap is NULL!");
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?});
?? ??? ?// MyTag可以隨便寫,可以寫應用名稱等
?? ??? ?PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
?? ??? ?// 換成PowerManager.SCREEN_DIM_WAKE_LOCK會變暗)
?? ??? ?PowerManager.WakeLock wl = pm.newWakeLock(
?? ??? ??? ??? ?PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyTest");
?? ??? ?wl.acquire();// 開啟屏幕常亮
?
?? ??? ?TV = (TextView) findViewById(R.id.TV);// 電池信息打印控件定義
?
?? ??? ?// 注冊一個系統 BroadcastReceiver,作為訪問電池計量之用,這個不能直接在AndroidManifest.xml中注冊
?? ??? ?registerReceiver(mBatInfoReceiver, new IntentFilter(
?? ??? ??? ??? ?Intent.ACTION_BATTERY_CHANGED));
?
?? ??? ?context = getApplicationContext();
?? ??? ?context1 = getApplicationContext();// 圖2
?? ??? ?// 這里獲得main界面上的布局,下面會把圖表畫在這個布局里面
?? ??? ?LinearLayout layout = (LinearLayout) findViewById(R.id.linearLayout1);
?
?? ??? ?// 這個類用來放置曲線上的所有點,是一個點的集合,根據這些點畫出曲線
?? ??? ?series = new XYSeries(title);
?? ??? ?series1 = new XYSeries(title);// 圖2
?? ??? ?// 創建一個數據集的實例,這個數據集將被用來創建圖表
?? ??? ?mDataset = new XYMultipleSeriesDataset();
?? ??? ?mDataset1 = new XYMultipleSeriesDataset();
?? ??? ?// 將點集添加到這個數據集中
?? ??? ?mDataset.addSeries(series);
?? ??? ?mDataset1.addSeries(series1);// 圖2
?? ??? ?// 以下都是曲線的樣式和屬性等等的設置,renderer相當于一個用來給圖表做渲染的句柄
?? ??? ?int color = Color.GREEN;
?? ??? ?int color1 = Color.RED;
?? ??? ?PointStyle style = PointStyle.CIRCLE;
?? ??? ?renderer = buildRenderer(color, style, true);
?? ??? ?renderer1 = buildRenderer(color1, style, true);// 圖2
?
?? ??? ?// 設置好圖表的樣式(橫軸時間分鐘值,縱軸電壓毫伏值)
?? ??? ?setChartSettings(renderer, "X", "Y", 0, 240, 3400, 4400, Color.WHITE,
?? ??? ??? ??? ?Color.WHITE);
?? ??? ?setChart1Settings(renderer1, "X", "Y", 0, 240, 0, 100, Color.WHITE,
?? ??? ??? ??? ?Color.WHITE);
?? ??? ?// 生成圖表
?? ??? ?chart = ChartFactory.getLineChartView(context, mDataset, renderer);
?? ??? ?chart1 = ChartFactory.getLineChartView(context1, mDataset1, renderer1);// 圖2
?? ??? ?</span><span style="font-size:12px;">// 將圖表添加到布局中去,此處的縱向尺寸設置存在一些問題,當兩張圖都設置<span style="font-family: Arial, Helvetica, sans-serif;">WRAP_CONTENT</span>時,在實際界面上只顯示第一張圖,在這里可根據手 ? ? ? ? ? ? ? ? ?// </span><span style="font-family: Arial, Helvetica, sans-serif;">機屏幕的大小設置具</span><span style="font-family: Arial, Helvetica, sans-serif;">體的數值(像素點個數),可以保證兩張圖都能顯示在屏幕上
</span><span style="font-size:14px;">?? ??? ?layout.addView(chart, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
?? ??? ?layout.addView(chart1, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
?? ??? ?// layout.addView(chart, new LayoutParams(LayoutParams.FILL_PARENT,
?? ??? ?// 400));//525
?? ??? ?// layout.addView(chart1, new LayoutParams(LayoutParams.FILL_PARENT,
?? ??? ?// 400));//圖2 525
?? ??? ?// 這里的Handler實例將配合下面的Timer實例,完成定時更新圖表的功能
?? ??? ?handler = new Handler() {
?? ??? ??? ?@Override
?? ??? ??? ?public void handleMessage(Message msg) {
?? ??? ??? ??? ?// 刷新圖表
?? ??? ??? ??? ?updateChart();// 電壓變化曲線刷新
?? ??? ??? ??? ?updateChart1();// 電量變化曲線刷新
?? ??? ??? ??? ?super.handleMessage(msg);
?
?? ??? ??? ?}
?? ??? ?};
?
?? ??? ?task = new TimerTask()// 刷新繪圖計時任務配置
?? ??? ?{
?? ??? ??? ?@Override
?? ??? ??? ?public void run() {
?? ??? ??? ??? ?Message message = new Message();
?? ??? ??? ??? ?message.what = 1;
?? ??? ??? ??? ?handler.sendMessage(message);
?? ??? ??? ?}
?? ??? ?};
?? ??? ?timer.schedule(task, 0, 60000);// 以一分鐘為時間間隔運行
?
?? ??? ?task1 = new TimerTask()// 保存繪圖計時任務配置
?? ??? ?{
?? ??? ??? ?@Override
?? ??? ??? ?public void run() {
?? ??? ??? ??? ?if (BatteryStatus == "充滿電"
?? ??? ??? ??? ??? ??? ?|| (BatteryStatus == "放電狀態" && BatteryN == 1))// 充/放電完成條件設定
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?button.callOnClick();// 保存曲線圖按鍵觸發
?? ??? ??? ??? ??? ?timer.cancel(); // 停止計時功能
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?};
?? ??? ?timer.schedule(task1, 0, 10000);// 以十秒鐘為時間間隔運行
?? ?}
?
?? ?@Override
?? ?public void onDestroy() // 結束程序聲明
?? ?{
?? ??? ?button.callOnClick();// 保存曲線圖按鍵觸發
?? ??? ?// 當結束程序時關掉Timer
?? ??? ?timer.cancel();
?? ??? ?// wl.release();
?? ??? ?// wl = null;
?? ??? ?super.onDestroy();
?? ?}
?
?? ?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((float) 1);// 線粗尺寸
?? ??? ?renderer.addSeriesRenderer(r);
?
?? ??? ?return renderer;
?? ?}
?
?? ?// 圖2
?? ?protected XYMultipleSeriesRenderer buildRenderer1(int color1,
?? ??? ??? ?PointStyle style, boolean fill)// 配置繪圖屬性
?? ?{
?? ??? ?XYMultipleSeriesRenderer renderer1 = new XYMultipleSeriesRenderer();// 圖2
?? ??? ?// 設置圖表中曲線本身的樣式,包括顏色、點的大小以及線的粗細等
?? ??? ?XYSeriesRenderer r = new XYSeriesRenderer();
?? ??? ?r.setColor(color1);
?? ??? ?r.setPointStyle(style);
?? ??? ?r.setFillPoints(fill);
?? ??? ?r.setLineWidth((float) 1);// 線粗尺寸
?? ??? ?renderer1.addSeriesRenderer(r);
?
?? ??? ?return renderer1;
?? ?}
?
?? ?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);
?? ??? ?renderer.setXTitle(xTitle);
?? ??? ?renderer.setYTitle(yTitle);
?? ??? ?renderer.setXAxisMin(xMin);
?? ??? ?renderer.setXAxisMax(xMax);
?? ??? ?renderer.setYAxisMin(yMin);
?? ??? ?renderer.setYAxisMax(yMax);
?? ??? ?renderer.setAxesColor(axesColor);
?? ??? ?renderer.setLabelsColor(labelsColor);
?? ??? ?renderer.setShowGrid(true);
?? ??? ?renderer.setGridColor(Color.GREEN);// 曲線顏色
?? ??? ?renderer.setXLabels(20);
?? ??? ?renderer.setYLabels(10);
?? ??? ?renderer.setChartTitle("時間/電壓變化曲線圖");// 圖表名稱
?? ??? ?renderer.setXTitle("時間(min)");// 橫坐標名稱
?? ??? ?renderer.setYTitle("電壓(mv)");// 縱坐標名稱
?? ??? ?renderer.setYLabelsAlign(Align.RIGHT);
?? ??? ?renderer.setPointSize((float) 1.5);// 設置點的大小
?? ??? ?renderer.setShowLegend(false);
?? ??? ?renderer.setPanEnabled(true, false);// 設置滑動,這邊是橫向可以滑動,縱向不可滑動
?? ??? ?renderer.setZoomEnabled(true, false);// 設置縮放,橫向可以,縱向不可以
?? ??? ?// renderer.setZoomLimits(new double[] { 0, 720, 3400, 4400 });//設置縮放的范圍
?? ??? ?// renderer.setPanLimits(new double[] { -0.5, 720, 3400, 4400
?? ??? ?// });//設置拉動的范圍
?? ?}
?
?? ?// 圖2
?? ?protected void setChart1Settings(XYMultipleSeriesRenderer renderer1,
?? ??? ??? ?String xTitle, String yTitle, double xMin, double xMax,
?? ??? ??? ?double yMin, double yMax, int axesColor, int labelsColor) {
?? ??? ?// 有關對圖表的渲染可參看api文檔
?
?? ??? ?renderer1.setChartTitle(title);
?? ??? ?renderer1.setXTitle(xTitle);
?? ??? ?renderer1.setYTitle(yTitle);
?? ??? ?renderer1.setXAxisMin(xMin);
?? ??? ?renderer1.setXAxisMax(xMax);
?? ??? ?renderer1.setYAxisMin(yMin);
?? ??? ?renderer1.setYAxisMax(yMax);
?? ??? ?renderer1.setAxesColor(axesColor);
?? ??? ?renderer1.setLabelsColor(labelsColor);
?? ??? ?renderer1.setShowGrid(true);
?? ??? ?renderer1.setGridColor(Color.GREEN);// 曲線顏色
?? ??? ?renderer1.setXLabels(20);
?? ??? ?renderer1.setYLabels(10);
?? ??? ?renderer1.setChartTitle("時間/電量變化曲線圖");// 圖表名稱
?? ??? ?renderer1.setXTitle("時間(min)");// 橫坐標名稱
?? ??? ?renderer1.setYTitle("電量(%)");// 縱坐標名稱
?? ??? ?renderer1.setYLabelsAlign(Align.RIGHT);
?? ??? ?renderer1.setPointSize((float) 1.5);// 設置點的大小
?? ??? ?renderer1.setShowLegend(false);
?? ??? ?renderer1.setPanEnabled(true, false);// 設置滑動,這邊是橫向可以滑動,縱向不可滑動
?? ??? ?renderer1.setZoomEnabled(true, false);// 設置縮放,橫向可以,縱向不可以
?? ??? ?// renderer1.setZoomLimits(new double[] { 0, 720, 0, 100 });//設置縮放的范圍
?? ??? ?// renderer1.setPanLimits(new double[] { -0.5, 720, 0, 100 });//設置拉動的范圍
?? ?}
?
?? ?private void updateChart()// 更新繪圖方法
?? ?{
?
?? ??? ?// 設置好下一個需要增加的節點
?? ??? ?addX = (int) (addX + 1);
?? ??? ?addY = BatteryV;
?? ??? ?// 移除數據集中舊的點集
?? ??? ?mDataset.removeSeries(series);
?? ??? ?// 判斷當前點集中到底有多少點,因為屏幕總共只能容納240個,所以當點數超過240時,長度永遠是240
?? ??? ?int length = series.getItemCount();
?? ??? ?if (length > 720) {
?? ??? ??? ?length = 720;
?? ??? ?}
?? ??? ?// 將舊的點集中x和y的數值取出來放入backup中,并且將x的值加1,造成曲線向右平移的效果
?? ??? ?for (int i = 0; i < length; i++) {
?? ??? ??? ?xv[i] = (int) series.getX(i);
?? ??? ??? ?yv[i] = (int) series.getY(i);
?? ??? ?}
?? ??? ?// 點集先清空,為了做成新的點集而準備
?? ??? ?series.clear();
?
?? ??? ?// 將新產生的點首先加入到點集中,然后在循環體中將坐標變換后的一系列點都重新加入到點集中
?? ??? ?// 這里可以試驗一下把順序顛倒過來是什么效果,即先運行循環體,再添加新產生的點
?? ??? ?series.add(addX, addY);
?? ??? ?for (int k = 0; k < length; k++) {
?? ??? ??? ?series.add(xv[k], yv[k]);
?? ??? ?}
?? ??? ?// 在數據集中添加新的點集
?? ??? ?mDataset.addSeries(series);
?
?? ??? ?// 視圖更新,沒有這一步,曲線不會呈現動態
?? ??? ?// 如果在非UI主線程中,需要調用postInvalidate(),具體參考api
?? ??? ?chart.invalidate();
?? ?}
?
?? ?// 圖2
?? ?private void updateChart1()// 更新繪圖方法
?? ?{
?
?? ??? ?// 設置好下一個需要增加的節點
?? ??? ?addX1 = (int) (addX1 + 1);
?? ??? ?addY1 = BatteryN;
?? ??? ?// 移除數據集中舊的點集
?? ??? ?mDataset1.removeSeries(series1);
?? ??? ?// 判斷當前點集中到底有多少點,因為屏幕總共只能容納240個,所以當點數超過240時,長度永遠是240
?? ??? ?int length1 = series1.getItemCount();
?? ??? ?if (length1 > 720) {
?? ??? ??? ?length1 = 720;
?? ??? ?}
?? ??? ?// 將舊的點集中x和y的數值取出來放入backup中,并且將x的值加1,造成曲線向右平移的效果
?? ??? ?for (int j = 0; j < length1; j++) {
?? ??? ??? ?xv1[j] = (int) series1.getX(j);
?? ??? ??? ?yv1[j] = (int) series1.getY(j);
?? ??? ?}
?? ??? ?// 點集先清空,為了做成新的點集而準備
?? ??? ?series1.clear();
?
?? ??? ?// 將新產生的點首先加入到點集中,然后在循環體中將坐標變換后的一系列點都重新加入到點集中
?? ??? ?// 這里可以試驗一下把順序顛倒過來是什么效果,即先運行循環體,再添加新產生的點
?? ??? ?series1.add(addX1, addY1);
?? ??? ?for (int l = 0; l < length1; l++) {
?? ??? ??? ?series1.add(xv1[l], yv1[l]);
?? ??? ?}
?? ??? ?// 在數據集中添加新的點集
?? ??? ?mDataset1.addSeries(series1);
?
?? ??? ?// 視圖更新,沒有這一步,曲線不會呈現動態
?? ??? ?// 如果在非UI主線程中,需要調用postInvalidate(),具體參考api
?? ??? ?chart1.invalidate();
?? ?}
?
?? ?/* 創建電池狀態廣播接收器 */
?? ?public BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
?? ??? ?public void onReceive(Context context, Intent intent) {
?? ??? ??? ?String action = intent.getAction();
?
?? ??? ??? ?// 如果捕捉到的action是ACTION_BATTERY_CHANGED, 就運行onBatteryInfoReceiver()
?
?? ??? ??? ?if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
?? ??? ??? ??? ?BatteryN = intent.getIntExtra("level", 0); // 目前電量
?? ??? ??? ??? ?BatteryV = intent.getIntExtra("voltage", 0); // 電池電壓
?? ??? ??? ??? ?// BatteryT = intent.getIntExtra("temperature", 0); //電池溫度
?
?? ??? ??? ??? ?switch (intent.getIntExtra("status",
?? ??? ??? ??? ??? ??? ?BatteryManager.BATTERY_STATUS_UNKNOWN)) {
?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_CHARGING:
?? ??? ??? ??? ??? ?BatteryStatus = "充電狀態";
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_DISCHARGING:
?? ??? ??? ??? ??? ?BatteryStatus = "放電狀態";
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
?? ??? ??? ??? ??? ?BatteryStatus = "未充電";
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_FULL:
?? ??? ??? ??? ??? ?BatteryStatus = "充滿電";
?
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case BatteryManager.BATTERY_STATUS_UNKNOWN:
?? ??? ??? ??? ??? ?BatteryStatus = "未知道狀態";
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?}
?
?? ??? ??? ??? ?switch (intent.getIntExtra("health",
?? ??? ??? ??? ??? ??? ?BatteryManager.BATTERY_HEALTH_UNKNOWN)) {
?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_UNKNOWN:
?? ??? ??? ??? ??? ?BatteryTemp = "未知錯誤";
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_GOOD:
?? ??? ??? ??? ??? ?BatteryTemp = "狀態良好";
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_DEAD:
?? ??? ??? ??? ??? ?BatteryTemp = "電池沒有電";
?
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
?? ??? ??? ??? ??? ?BatteryTemp = "電池電壓過高";
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?case BatteryManager.BATTERY_HEALTH_OVERHEAT:
?? ??? ??? ??? ??? ?BatteryTemp = "電池過熱";
?? ??? ??? ??? ??? ?break;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?TV.setText("目前電量為" + BatteryN + "% --- " + BatteryStatus + "\n"
?? ??? ??? ??? ??? ??? ?+ "電壓為" + BatteryV + "mV ----- " + BatteryTemp);
?
?? ??? ??? ?}
?? ??? ?}
?
?? ?};
?
?? ?@Override
?? ?public boolean onKeyDown(int keyCode, KeyEvent event)// 程序按返回鍵退出處理
?? ?{
?? ??? ?switch (keyCode) {
?? ??? ?case KeyEvent.KEYCODE_BACK:
?? ??? ??? ?// 雙擊退出
?? ??? ??? ?// if (isStart == true){isStart = false;}//關閉前確認頻閃是否關閉
?? ??? ??? ?if ((System.currentTimeMillis() - mExitTime) > 2000) {
?? ??? ??? ??? ?Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
?? ??? ??? ??? ?mExitTime = System.currentTimeMillis();
?? ??? ??? ?} else {
?? ??? ??? ??? ?// isStart = false;
?? ??? ??? ??? ?finish();
?? ??? ??? ?}
?? ??? ??? ?return true;
?
?? ??? ?default:
?? ??? ??? ?break;
?? ??? ?}
?? ??? ?return super.onKeyDown(keyCode, event);
?? ?}
?
}
布局文件:
<?xml version="1.0" encoding="utf-8"?> ? <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"? ? ? android:id="@+id/linearLayout1" ? ?? ? ? android:orientation="vertical" ? ? ? android:layout_width="fill_parent" ? ? ? android:layout_height="fill_parent" ? ? android:layout_weight="1" ? ? > ? <!-- ?--> <TextView ? ? ? android:id = "@+id/TV"? ? ? ?? ? ? android:layout_width="fill_parent" ? ? ? android:layout_height="wrap_content"? ? ?? ? ? /> ? ?? <Button ? android:text="保存該曲線圖" ? android:textSize="4pt" ? android:id="@+id/my_button" ?? ? android:layout_width="fill_parent" ? android:layout_height="28dp" ? android:layout_alignBottom="@+id/TV"> ? <!--android:layout_alignParentBottom="true"--> ?? </Button> </LinearLayout>
AndroidManifest.xml配置文件
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ? ? package="com.cfzz.vcd" ? ? android:versionCode="1" ? ? android:versionName="1.0">? ? ?? ? ? <uses-sdk android:minSdkVersion="10" /> ? ? <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/> ? ? <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> ? ? <uses-permission android:name="android.permission.WAKE_LOCK" /> ? ? ? <application ? ? ? ? android:icon="@drawable/ic_launcher" ? ? ? ? android:label="@string/app_name" > ? ? ? ? <activity android:name="org.achartengine.GraphicalActivity" /> ? ? ? ? <activity ? ? ? ? ? ? android:name="com.cfzz.vcd.VoltageChangeDraw" ? ? ? ? ? ? android:screenOrientation="portrait" ? ? ? ? ? ? android:label="@string/app_name" > ? ? ? ? ? ? <intent-filter> ? ? ? ? ? ? ? ? <action android:name="android.intent.action.MAIN" /> ? ? ? ? ? ? ? ? ? <category android:name="android.intent.category.LAUNCHER" /> ? ? ? ? ? ? </intent-filter> ? ? ? ? </activity> ? ? </application> ? </manifest>
在該源碼中,我們繪制了兩條曲線,一條是電壓變化曲線,另一條是電量變化曲線,并加一個保存手機屏幕的截圖按鈕和自動保存時間任務(也可手動保存),用來保存繪制的截圖。
運行結果圖(充電曲線圖):
原文鏈接:https://blog.csdn.net/best2012power/article/details/49950195
相關推薦
- 2022-05-31 Python學習之yaml文件的讀取詳解_python
- 2022-05-07 react?源碼中位運算符的使用詳解_React
- 2022-07-12 Linux環境Jenkins部署
- 2022-05-25 utf8_unicode_ci和utf8_general_ci區別
- 2022-01-27 worker process terminated 進程退出
- 2022-06-28 python神經網絡Keras構建CNN網絡訓練_python
- 2022-12-14 Android使用Room操作數據庫流程詳解_Android
- 2022-03-26 淺談C語言數組元素下標為何從0開始_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支