下面這段影片顯示氣壓計(Barometer)的即時動態折線圖,網路上一直找不到現成的realtime圖表函數庫,Jimmy's papa只好動手修修改改別人的範例,花了許久的時間才做到能夠即時更新線圖畫面
這裡是Jimmy的實驗室用來發表Jimmy的Scratch程式作品,還有LEGO WEDO & NXT機器人設計 & Android, (本部落格引用圖文為教育教學目的合理使用) 想與我(Jimmy的爸爸 )聯絡 jimmyscratchlab@gmail.com
2011年9月10日 星期六
2011年9月7日 星期三
原來Java List類別是Hold住哥
最近Jimmy's papa被List類別搞得快變成卡卡先生,進度一直卡卡卡,原本Jimmy's papa想為android寫個即時動態折線圖(realtime Line Chart),可是事與願違,折線圖永遠只顯示最初的十筆資料,後來發現,原來搗蛋的是List這個Hold住哥
以下是部份程式碼
//dataArraylist存放每條折線的所有資料點的x及y值
private ArrayList<GraphViewData> dataArraylist = new ArrayList<GraphViewData>();
//lineGraphSeries可存放多條折線
private List<LineGraphViewSeries> lineGraphSeries;
//將dataArraylist塞入exampleSeries
exampleSeries = new GraphViewSeries(dataArraylist);
lineGraphView.addSeries(exampleSeries);
這個Thread會每隔0.5秒寫入一筆資料,填滿十筆資料後再開始顯示折線圖,"理論上"折線圖會一直更新,但"沒有"
runOnUiThread(new Runnable() {
public void run() {
dataArraylist.add(new GraphViewData(
0.5 * (dataArraylist.size()+1),pressure_value));
if(dataArraylist.size()>10)
{
drawLineGraph();
}
}
最後Jimmy's papa的解法是,每次update UI之前就將折線物件清掉
lineGraphSeries.clear();
然後再次執行
exampleSeries = new GraphViewSeries(dataArraylist);
lineGraphView.addSeries(exampleSeries);
就OK了
ps.Jimmy's papa懷疑這是否是因為ArrayList的某些內部資料成員被設為final的關係?
2011年8月26日 星期五
想榨乾XOOM的電力嗎?試試看這個會隨時更新Sensor值的Widget
![]() |
| 寄件者 scratchlab |
Jimmy's papa想試試看在XOOM上,是否能隨時按Home鍵後回到主畫面後,就有個氣壓計小工具(Widget)告訴我目前的氣壓值,這工具可以教Jimmy看著氣壓值並且對照戶外的天氣,去了解兩者之間的關係,而且順便讓Jimmy回想一下上個月到科工館玩氣壓體驗艙當時的感覺
不過Jimmy's papa寫這個小工具時,竟然發覺氣壓值無法更新,一查之下android:updatePeriodMillis這個屬性竟然Android 1.5版後就沒效了(這是網友說的,有待查證),官方文件也提到"Updates requested with updatePeriodMillis will not be delivered more than once every 30 minutes."
解決之道有AlarmManager或TimerTask兩種方式解決,Jimmy's papa覺得TimerTask比較簡單,以下是程式碼
package com.jimmyscratchlab.androidbarometerwidget;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.text.format.DateFormat;
import android.util.Log;
import android.widget.RemoteViews;
public class AndroidBarometerWidget extends AppWidgetProvider {
private static final String TAG = "sensor";
private SensorManager sm;
private String value = "";
@Override
public void onUpdate(Context context,AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// TODO Auto-generated method stub
sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
int sensorType = Sensor.TYPE_PRESSURE;
sm.registerListener(myPressureListener,sm.getDefaultSensor(sensorType),SensorManager.SENSOR_DELAY_NORMAL);
Timer timer = new Timer();
timer.scheduleAtFixedRate(new MyTime(context, appWidgetManager), 1, 500);
}
private class MyTime extends TimerTask
{
RemoteViews remoteViews;
AppWidgetManager appWidgetManager;
ComponentName thisWidget;
public MyTime(Context context, AppWidgetManager appWidgetManager)
{
this.appWidgetManager = appWidgetManager;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
thisWidget = new ComponentName(context, AndroidBarometerWidget.class);
}
@Override
public void run()
{
remoteViews.setTextViewText(R.id.now, value);
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}
}
final SensorEventListener myPressureListener = new SensorEventListener(){
public void onSensorChanged(SensorEvent sensorEvent){
if(sensorEvent.sensor.getType() == Sensor.TYPE_PRESSURE){
Log.i(TAG,"onSensorChanged");
java.text.DecimalFormat df = new java.text.DecimalFormat("#.#");
value = "目前氣壓(PRESSURE): "+ df.format( sensorEvent.values[0] )+"millibars";
}
}
public void onAccuracyChanged(Sensor sensor , int accuracy){
Log.i(TAG, "onAccuracyChanged");
}
};
}
訂閱:
文章 (Atom)
