AndroidのGUIと非同期処理
Androidでは(基本的には一般的な話ですが)、時間のかかる処理はメインのスレッドに記述するのではなく、別のスレッドで非同期に処理するようにします。例えば、ファイルの読み込みであったり、ダウンロードしたりするような処理です。
その場合、処理した結果を画面に反映したいことが多いでしょう。ここで問題になるのが、前回書いたとおり、AndroidのGUIがシングルスレッドモデルだということです。GUIの更新は、メインのスレッド(GUIスレッド)に限定されていますので、別スレッドの中から直接GUIの更新が行えません。間違えて更新すると例外が発生してしまいます。
別スレッドからのGUI更新
Androidでは、別スレッドからGUIを更新するには、直接GUIを更新するのではなく、GUIスレッドに対してGUI更新の通知を送るようにします。そして通知を受けとったGUIスレッドが、代わりにGUI更新を行うという形です。
この通知(メッセージ)のやりとりに、Androidでは、メッセージキューという仕組みが利用されています。メッセージキューとは、その名のとおり、メッセージのキュー(Queue)という意味です。
メッセージキュー
一般にメッセージキューを使った処理のながれは、次のようになります。
- メッセージの送り手は、受け手のメッセージキューにメッセージを格納する。
- 受け手側は、メッセージキューにメッセージがあるかどうかを監視する。
- メッセージがあれば、メッセージを1つだけとりだす。
- 受け手側がメッセージに従って処理を行う。
LooperクラスとHandlerクラス
Androidでのメッセージキューの処理は、android.os.Looperとandroid.os.Handlerの2つのクラスが担っています。
Looperクラスの役目は、かんたんに言うと、メッセージキューを持ち、そのキューからメッセージをとりだして処理を行うことです。一方のHandlerクラスは、特定のメッセージキューにメッセージを格納するためのものです。
Looperクラスは、スレッドごとに独自にインスタンス化することができます。ただし、Activityクラスを継承したメインスレッドでは、すでに内部でLooperオブジェクトが生成されています。そのため、GUIの更新に利用するだけであれば、特にLooperオブジェクトを意識する必要はありません。じつは、ActivityクラスのOnCreateメソッドやOnResumeメソッドなどは、Looperオブジェクトが呼び出しているのです。
Handlerクラスの使い方
Handlerクラスをインスタンス化すると、デフォルトでは、同じスレッドにあるLooperオブジェクトとメッセージキューに関連づけられます。その後、GUI更新を行うタイミングで、Handlerオブジェクトのメソッド(sendMessageメソッドやpostメソッド)を呼び出し、メッセージキューにメッセージを投入します。
なお、この場合のメッセージは、文字通りのメッセージだけでなく、オブジェクトも含まれます。例えば、処理を記述したオブジェクトをメッセージキューに格納すれば、GUIスレッドがメッセージを取得したタイミングで、そのオブジェクトの処理を行う、ということが可能です。
