View on GitHub
mixi-inc/AndroidTraining
HandlerとLooper
この章では、Handler と Looper について解説します。

参考:Communicating with the UI thread | Android Developers
参考:Handler | Android Developers
参考:Looper | Android Developers

目次

Looper

Looperは、Looperが初期化されたスレッド内で作られたメッセージを順に処理するオブジェクトです。
Activity などのコンポーネントでは、標準でこのLooperが UI スレッド上で初期化されます。これによって、Activity や Fragment で受け取った UI のイベントをメッセージとしてLooperに投げると、メインスレッド上でそのメッセージが実行されるようになります。

メインスレッド用のLooperを取得する場合は以下のようにします。

Looper looper = Looper.getMainLooper();

Looperは、その初期化を実行したスレッド内でメッセージを順に処理するように振舞うので、UI スレッドでない別のスレッドにも適用できます。
こうすることで、別スレッドにおいても、何らかのイベントをメッセージとして受け付けることが出来るようになります。

public class MyThread extends Thread {
    @Override
    public void run() {
        Looper.prepare(); // 初期化
        // ...
        Looper.loop(); // メッセージキューを開始
    }
}

Handler

Looperの仕組みによって、メッセージを受け付けて順に処理できるようになりますが、一方で、Looperに対してメッセージを送る役割を持つものが必要になります。

この、Looperに対してメッセージを送る役割を担っているのがHandlerです。
多くは、別スレッドから UI スレッドへメッセージを送ることで、別スレッド内で UI の更新を促す為の仕組みとして用いられます。

下記のようにHandlerインスタンスを生成すると、生成したインスタンスのLooperにメッセージを送るHandlerが作られます。

Handler handler = new Handler();

もし、メインスレッドの Looper にメッセージを送るHandlerインスタンスを生成する場合は、以下のようにします。

Handler handler = new Handler(Looper.getMainLooper());

メッセージを作成し、その内容をLooperのキューに積んで実行させるには、以下のようにします。

Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
    @Override
    public void run() {
        // メインスレッド上で実行させたい内容
    }
});

HandlerThread

Handlerを内部に持ち、Looperが動作していて、適宜そのLooperにメッセージを積み上げて処理することの出来る特別なThreadです。 HandlerThreadのインスタンスが生成された時、Looper#prepare()が呼び出され、Looperの動作が始まります。この後、このスレッド用にHandlerが生成され、他のスレッドとのメッセージのやり取りが出来るようになります。

IntentServiceは内部的にHandlerThreadを使用しており、Context#startService(Intent)で渡されたIntentを順にHandlerを経由してHandlerThreadに渡しています。これによって、簡易的なジョブキューの仕組みが実現されています。