2011年9月10日 星期六

Android Realtime Line Chart Demo

下面這段影片顯示氣壓計(Barometer)的即時動態折線圖,網路上一直找不到現成的realtime圖表函數庫,Jimmy's papa只好動手修修改改別人的範例,花了許久的時間才做到能夠即時更新線圖畫面

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");
        }
    };
     
}