私は、メッセージを処理するバックグラウンドで座っているワーカースレッドを持っています。このような何か:ルーパースレッドを作成してすぐにメッセージを送信する方法は?
class Worker extends Thread {
public volatile Handler handler; // actually private, of course
public void run() {
Looper.prepare();
mHandler = new Handler() { // the Handler hooks up to the current Thread
public boolean handleMessage(Message msg) {
// ...
}
};
Looper.loop();
}
}
メインスレッドから(UIスレッドではなく、それは重要なこと)私はこのような何かをしたいと思います:
Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);
トラブルは、これがために私を設定していることです美しい競合状態:時刻がworker.handler
のとき、ワーカースレッドがすでにこのフィールドに割り当てられていることを確認する方法はありません!
Handler
は、Worker
のコンストラクタから単純に作成できません。コンストラクタはメインスレッド上で実行されるため、Handler
は間違ったスレッドに関連付けられます。
これはまれなシナリオのようです。このような
は何か:
class Worker extends Thread { public volatile Handler handler; // actually private, of course public void run() { Looper.prepare(); mHandler = new Handler() { // the Handler hooks up to the current Thread public boolean handleMessage(Message msg) { // ... } }; notifyAll(); // <- ADDED Looper.loop(); } }
そして、メインスレッドから:私はいくつかの回避策、醜い、それらのすべてを考え出すことができる
Worker worker = new Worker(); worker.start(); worker.wait(); // <- ADDED worker.handler.sendMessage(...);
しかし、これはどちらか信頼できるものではありません:の前に
notifyAll()
が発生した場合、私たちは目が覚めることはありません!run()
メソッドを持つWorker
のコンストラクタに最初のMessage
を渡します。アドホックなソリューションは、複数のメッセージに対しては機能しません。すぐに送信したくない場合はすぐに送信します。handler
フィールドがもはやnull
になるまでビジー状態です。うん、...
最後の私はWorker
スレッドに代わってHandler
とMessageQueue
を作成したいと思いますが、これは可能ではないようです。この中で最もエレガントな方法は何ですか?
あなたは 'HandlerThread'を使用していない任意の特定の理由は? – CommonsWare
@CommonsWare:うーん、それが存在することを知らなかった。ドキュメント内に相互参照はありません。その 'getLooper()'メソッドは、 'Looper'を持つまでブロックします。そして、メインスレッド*から' Handler'を初期化するために 'new Handler(worker.getLooper())' *を使うことができます。それは問題を解決するでしょう、そうですか? – Thomas
そうだと思います。 OTOH、私は自分自身でそれをあまり使っていないので、何かを見逃しているかもしれません。 – CommonsWare