どこが難しいかは、やはり、イベント絡みでスレッドを意識しなくてはならない事にあります。同じイベントでも、カメラのコールバックと、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 件のコメント:
コメントを投稿