AndroidのHandlerについて、あまりよく分からなかったのですが、調べて分かったことを覚書しておきます。
Handler を理解する上で知っておきたい事
Handlerについて理解するには、まずAndroidの基本的なルールを知っておくと理解しやすくなります。
そのため、まずはそのルールについて書き、そこからHandlerの用途に迫ってみます。
Androidアプリにはルールがある!
Androidアプリの基本であるActivityは、Looperと言われるスレッド上で動いています。
このスレッドは、UIを制御しているのでUIスレッドと呼ばれています。(※Looper = UIスレッドではありません。Looperはいくつもあり、アクティビティを動いている LooperをUIスレッドと言います)
ここで大事なポイントです。
Androidアプリには
- 重たい処理をUIスレッドで行ってはならない
- UIの更新は必ずUIスレッド上で行う
というルールがあります。
これを知らずに開発をすると、重たい処理をした時に、ソースコード上、バグは無いのになぜか強制終了という意味不明な自体が起こったりします。
複数スレッドで起こる同期の問題
例えば、巨大なテキストファイルを読み込んで、その情報をテキストビューに表示することを考えてみます。
- スレッドを起動
- スレッドからテキストファイルを読み取る
- 読み取った情報をテキストビューに反映
この手順で行けそうですが、これだと問題が出てきます。
Androidのルール上、巨大なファイルの読み込みは非UIスレッドで行わなくてはいけません。
つまり、上記手順の2番はUIスレッドとは別のスレッドで行うことになります。
しかし、上記手順の3番(読み取った情報をテキストビューに反映)はUIスレッドで行わないといけないのです。
テキストファイルの読み込みは別スレッドで行っているので、UIスレッド上ではいつ読み込みが終わったか分かりません。
つまり、UIスレッドと同期が取れないのです。
どうやってUIスレッドに同期させればよいのでしょうか…?
Handlerはスレッド間の通信をする仕組み
これを解決するのがHandlerとRunnanleという仕組みです。
HandlerとはLooperに対して命令を出すための仕組みなのです。
命令は、特殊な数字や記号などではなくRunnableというインターフェースです。
RunnableはRunというメソッドを実装する必要があります。
HandlerはRunnableをLooperに渡してくれるのです。
LooperはHandlerからRunnableを受けると、それを自身のスレッドで実行してくれます。
つまり、自身で実装したRunメソッドをLooper上で実行してくれるわけです。
Handlerは、どんなスレッドからでも使うことができます。
Handlerを使って、非UIスレッドからUIスレッドに対してRunnableを渡してあげれば、非UIスレッド上からでもUIスレッドに処理をさせることができるのです。
この仕組みを使えば、テキストファイルを読み込み完了後にUIを更新することができます。
Handlerの使い方
使い方は簡単です。
HandlerとRunnabkeのインスタンスを作成してHandler#postというメソッドにで設定するだけです。
public void HandlerTest() { Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { } }; handler.post( runnable ); }
この場合、Handler#postを実行したらUIスレッドでrunが実行されます。
Runnableを遅延して実行をさせたいときは、Habdler#postDelayを使います。
public void HandlerTest() { Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { } }; handler.postDelayed( runnable, 1000 ); }
ディレイ時間はミリ秒です。この場合は、1秒後にrunがUIスレッド上で実行されます。
Runnableのメソッド内で繰り返しpostDelayを実行すれば簡易的なタイマーにすることもできます。
かなり便利です。
Handlerの問題点は?
Handlerの問題点は、スリープ状態になると動かなくなることがあります。
dozeモード時も動きません。
そのため、この機能で目覚まし時計を作るのはNGですね。
本来の目的は、Looperに対して命令を出すことです。
スレッドやタイマーの例としてよく使われていますが、実際はスレッドでもタイマーでもありません。
これを知らないとまた思わぬバグに繋がるので注意しないといけませんね。
Android 難しい…
スポンサーリンク