非同期処理と UI の更新

時間のかかる処理をクリックイベントハンドラ等で直接行ってしまうと、画面全体がフリーズしてしまいます。

これはメインスレッドで GUI (グラフィカルユーザーインターフェイス) の処理を行っているからです。(このときメインスレッドが GUIスレッドになっている、といいます)

したがって、時間のかかる何らかの処理を行って、それを UI に反映させたい場合、そしてその間画面をフリーズさせたくない場合 (普通そうですよね?) は、 その時間のかかる処理をメインスレッドではない、作業用のスレッド (ワーカースレッド) で行うと良いでしょう。

しかし、処理結果を UI に戻そうとするとちょっと厄介なことになります。 GUI の処理は GUI スレッドで行わなければならないからです。つまり、 ワーカースレッドでは view.setText("Done!") というようなコードを直接呼んではいけないのです。

それでは、一体どうしたらよいのか? ということをここで説明します。

Handler で GUI スレッドに処理をポスト

GUI スレッドに処理をポストするには、 Handler オブジェクトを利用します。

GUI スレッドにはメッセージキューが関連付けされています。 GUI スレッドではそのメッセージキューから処理を取り出して一つ一つ処理をすることによって、イベント処理を行ったり、 GUI コンポーネントの描画を行うなどしています。

このループの中でイベントハンドラが呼び出されたりします。

Handler オブジェクトを経由して、それを作成したスレッドのメッセージキューに、メッセージを送ったり Runnable オブジェクトをポストすることが可能になります。

コード例は次のようになります。

package com.keicode.android.test;

import android.os.Handler;
...

public class AsyncTest1 extends Activity 
    implements OnClickListener {
  
    Handler guiThreadHandler;
    ...  

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        guiThreadHandler = new Handler();
        ...
    }
    ...
    
    public void setTextAsync(final String text){
      guiThreadHandler.post(new Runnable(){
        @Override
        public void run() {
          view.setText(text);
        }      
      });
    }
  }

このような setTextAsync メソッドを用意しておき、 ワーカースレッドからこのメソッドを呼び出すことによって、 GUI スレッドに UI 更新用のタスクを投げることができるようになります。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門