非同期処理と UI - 基本的な枠組み

非同期で処理したい時間のかかる処理を含むプログラムの骨組みの例を示します。

なぜ Handler を使わなければならないのか? とか、 ExecutorService ってなんだ? とか、 そういった点については別のページを参考にしてください。

ここでは Android でワーカースレッドで処理を行って、 GUI にその結果を戻すような場合の典型的な骨組みを示します。

このプログラムの完成形

何を作っているか見えた方がわかりやすいと思いますので、実行例のスクリーンショットをとりました。

画面の Test ボタンをクリックすると、 "Now Processing..." (処理中です) という文字が表示されます。

Android 非同期処理

が、実際には何も処理をせずに5秒間だけじーっとして、5秒後に "Done!"というメッセージに切り替わります。

Android 非同期処理

この間、画面はフリーズしません。押そうと思えば、 "Now Processing..." と表示中にももう一度 Test ボタンを押すことも出来ます。

コード例

メッセージを表示する部分とボタンは、それぞれ TextView と Button ウィジェットを配置しています。全体はリニアレイアウトになってます。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
	android:id="@+id/result"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text=""
    android:textSize="30sp"
    />
<Button
    android:id="@+id/test_button"
    android:text="Test"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="30sp"
    />
</LinearLayout>

アプリケーションのコードは次のとおりです。

package com.keicode.android.test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class AsyncTest1 extends Activity 
    implements OnClickListener {
  
  TextView resultTextView;
  Button testButton;
  
  Handler guiThreadHandler;
  ExecutorService asyncExecutorService;
  Runnable starterTask;
  @SuppressWarnings("unchecked")
  Future taskPending;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    findViews();
    setListeners();
        
    guiThreadHandler = new Handler();
    asyncExecutorService = Executors.newSingleThreadExecutor();
    starterTask = new Runnable(){
      @Override
      public void run() {
        try{
          MyAsyncTask asyncTask = 
            new MyAsyncTask(AsyncTest1.this);
          taskPending = 
            asyncExecutorService.submit(asyncTask);
        }
        catch(RejectedExecutionException e){
          resultTextView.setText("Error");
        }
      }          
    };
        
  }
    
  protected void findViews(){
    resultTextView = (TextView)findViewById(R.id.result);
    testButton = (Button)findViewById(R.id.test_button);
  }
    
  protected void setListeners(){
    testButton.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
    switch(v.getId()){
    case R.id.test_button:
      startAsyncTask();
      break;
    }
  }
    
  protected void startAsyncTask(){
    guiThreadHandler.removeCallbacks(starterTask);
    guiThreadHandler.postDelayed(starterTask, 200);
  }
    
  public void setTextAsync(final String text){
    guiThreadHandler.post(new Runnable(){
      @Override
      public void run() {
        resultTextView.setText(text);
      }      
    });
  }
}

いろいろなオブジェクトが登場していますが、ここでは説明しません。次のページを参考にしてください。

長い処理をシミュレートするタスクは次のようになってます。ここでは GUI スレッドに処理をポストするメソッドを呼んでいます。

package com.keicode.android.test;

public class MyAsyncTask implements Runnable {

  AsyncTest1 test1;
  
  public MyAsyncTask(AsyncTest1 test1){
    this.test1 = test1;
  }
  
  @Override
  public void run() {
    test1.setTextAsync("Now processing...");
    String result = doTask();
    test1.setTextAsync(result);
  }
  
  public String doTask(){
    String result = "Done!";
    
    try{
      if(Thread.interrupted()){
        throw new InterruptedException();
      }
      Thread.sleep(5 * 1000);
    }
    catch(InterruptedException e){
      result = "Interrupted";
    }
    
    return result;
  }

}

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

© 2024 Android 開発入門