2011年11月12日土曜日

AFreeChartを動的に動かす

AFreeChartに関する情報が少ないと感じたので少しでも役に立てれば..

【やりたいこと】
Androidアプリでグラフを表示したい。
しかも動的(リアルタイム的な)に動かしたい!
※)TimeSeriesのサンプルをベースとする。

グラフ表示ライブラリを探した所いくつかあると言うことがわかった。
直感的にAFreeChartが一番良さそうな感じがしたので使うことにした!

AFreeChartの導入方法に関しては他のブログで書いている方が
いらっしゃるので割愛します。

サンプルソースを実行すると静的なグラフを表示することは簡単にできます。
動的にするにはAFreeChartが保有しているDatasetにデータを追加してあげると
自動的に再描画される。

なので、最初に思いつく方法としては動的にDatasetを更新して行けばできる、
だとうという方法です。
例えば、別スレッドを用意して100msごとにDatasetを更新するようなプログラムを
作って動かすとあることに気付くと思います。データ数が増えるに連れて、
恐らくGCが高頻度で発生し、
描画に時間がかかりUIスレッドに負担がかかり、
ANRを引き起こす可能性があります。

結果的にDatasetの更新をトリガーとして再描画して動的に見せる方法では、
限界があるということになります。

デフォルトのサンプルアプリだと、生成したAFreeChartインスタンスに
ChartChangeListenerがセットされているので、Dataset更新すると再描画が発生する。
それを抑えるためにはBaseView(511行目前後)でリスナーセットする処理をコメントアウトするか、
リスナーを登録を削除するか、
しないとダメです。

そうすると、Datasetを更新しても再描画されることはなくなります。
この状態だと再描画がなくてリアルタイムに見えません。

現段階での私のソリューションとしては以下のような感じです。

①Dataset更新用スレッド、再描画用スレッドの2つを生成する
②それぞれをstartさせる
③再描画スレッドは定期的にHandlerに対してView#postInvalidateを呼び出すだけ

パッと思いついただけの方法なので、もっと効率のいい方法があったら
ご教授願いますm(_ _)m

再描画スレッドは以下のような感じです。(一部抜粋)
もちろんこのままでは動かないので適宜に補完してください^^;

repaintThread = new Thread(new Runnable() {
  public void run() {
   while (!stop) {
    if (pause)
     pause();
    mainHandler.post(new Runnable() {
     public void run() {
      // repaint();
      timeChartView.postInvalidate();
     }
    });
    try {
     Thread.sleep(interval);
    } catch (InterruptedException e) {
     // TODO 自動生成された catch ブロック
     e.printStackTrace();
    }
   }
  }
 });
 repaintThread.start();