どこが難しいかは、やはり、イベント絡みでスレッドを意識しなくてはならない事にあります。同じイベントでも、カメラのコールバックと、GPSのイベント通知では機構が異なり、ライブラリの設計そのものが変です。
カメラのコールバック Camera.takePicture で登録したイベントは、推定、Android 実機の実装に依存しそうで、IS03 では、Activity のメインスレッド外で発生します。そのため、巷のコードはアプリケーション・エラーでハングするか、ハングする可能性が高いものが流通しています。 IS03で、カメラをオープンしているアプリがハングすると、どうなるか?電源を切って再起動するまで、カメラが開けません。
Camera.startPreview のコードは、Camera.takePicture の直後に置いては、いけません。スレッドの競合を起こします。 もし、Camera.startPreview が Activity のメインスレッドから呼ばれなければならないのであれば、Handler を使ってコールするように Runnable を post する必要があります。この辺の基準は、正直わかりません。何故なら、Android のライブラリ設計者も、よくわかっていない節があるからです。
Handler は特殊で、ハンドラを生成したメッセージループ Looper スレッドに作用します(実行時のカレントスレッドに作用します)。Handler を保持するクラスに作用するのではありません。従って、別スレッドから、メインスレッドで実行したいコードは、Runnable クラスとして、Handler に post させます。
宣言は、どこでも良いが、スコープには注意した方が良い(Javaは関係ない?)という意味で同一クラスに置く。
Handler handler_ = null;
handler_ = new Handler();する必要があります。Activity に限定すれば、@Override を施したメソッド内で new Handler() をすればよい。ただし、生成は1回のみで十分なので、自ずと onCreate() や、メンバ変数宣言で Handler handler_ = new Handler(); するのが妥当。
ルーパースレッドでは、
public void run() { Looper.prepare(); handler_ = new Handler(); Looper.loop(); }とするのが良いでしょう。
これに対して、Callback 系のメソッドや、ワーカースレッドなどの別スレッドから、UI に関わるようなメインスレッドで実行しなければならないコードは、
public void postHoge() { handler_.post( new Runnable() { @Override public void run() { // メインスレッドで実行したいコード hoge(); } } ); }というコードを用意しておいて、別スレッドから
// Activity のメソッドであれば postHoge(); // ルーパースレッドのメソッドであれば looperThread_.postHoge();
というようにコールすれば良いようです。
ルーパースレッドを終了させるスマートな方法は、ルーパースレッドのメソッドとして
public void postExit() { handler_.post( new Runnable() { @Override public void run() { Looper.myLooper().quit(); } } ); }定義したものを、looperThread_.postExit(); してやる事です。looperThread_.interrupt(); するよりは良いでしょう。
まだ、Handler の使いかたは、いろいろあるようですが、難しすぎです。
追記:
2011/02/16 修正 どこでもよい -> 同一クラスに置く,
2011/02/20 修正 どこでもよい -> OK
handler_.post() に相当する関数 runOnUiThread なるものがあるらしい。こいつを使うと
Handler handler_ = new Handler();を省略できて、かわりに
public void postHoge() { runOnUiThread( new Runnable() { @Override public void run() { // メインスレッドで実行したいコード hoge(); } } ); }と、できるようだ。
0 件のコメント:
コメントを投稿