AsyncTaskについて

目次へ

AsyncTaskとは

Androidでは、ユーザがアプリを起動すると、UIスレッド(メインスレッド)が作成され、 ユーザがタップするなどのイベントが発生すると、メッセージキューにそのイベントが並び、順番に実行されていきます。
そのため、UIスレッド上で実行する処理が非常に長いと、メッセージキューの次に並んでいる処理が実行できなくなるため、 UIスレッドでは、長い処理を行ってはいけないことになっており、通信などの長い時間のかかる処理は 別のスレッドを作成してその中で実行することになります。
しかし、画面の操作などは、UIスレッドでしか実行することができません。 UIスレッド以外のスレッドで、UIオブジェクトを参照したり変更したりするとクラッシュ、その他の不正動作が発生する可能性があります。
そのため、別スレッドからその結果を、画面に表示するなどの場合に使うのが、HandlerあるいはAsyncTaskです。 同じことができますが、ここではAsyncTaskを説明しますので。Handlerについてはこちらをご覧ください。

AsyncTaskの実装と実行

AsyncTaskはThreadやRunnableを意識せず、別スレッドで実行したい処理を記述することができ、 さらにUIスレッドで実行する処理も記述できる抽象クラスです。

AsyncTaskの重要なメソッドはdoInBackgroundで、別スレッドで実行したい処理を記述します。 このメソッドは抽象メソッドであり必ず実装する必要があります。
この別スレッドでの処理に応じて画面を操作するために、onPreExecute、onPostExecute、 onProgressUpdateなどのメソッドがあります。 この3つのメソッドに書いた処理はUIスレッドで実行されますので、画面の操作ができます。 これらは、必要が無ければオーバーライドする必要はありません。

  • doInBackground
     別スレッドで行う処理を書くメソッド
  • onPreExecute
     doInBackground開始前に呼び出される(UIスレッドで実行)
  • onPostExecute
     doInBackground終了後呼び出される(UIスレッドで実行)
  • onProgressUpdate
     doInBackgroundの中でpublishProgressを呼び出すと実行される(UIスレッドで実行)

AsyncTask<Params, Progress, Result>のジェネリクスは左から doInBackgroundの引数、onProgressUpdateの引数、doInBackgroundの戻り値 (=onPostExecuteの引数)となります。

このクラスの実行はインスタンスを作成し、executeメソッドを呼び出します。
executeの引数は可変個引数で、doInBackgroundに配列で渡されます。

AsyncTaskを使う例

task.executeの引数が無いのは、可変個引数なので無でもよいためです。

MyAsyncTaskクラスをstaticにしているのは、外部クラスとの関係が比較的薄くなるように しています。

onProgressUpdateの引数が可変個になっているのは、publishProgressの1回の呼び出しで 必ずonProgressUpdateが1回呼び出されると決まっているわけではなく、publishProgressの 複数回の呼び出しがまとめて、onProgressUpdate1回の呼出になる可能性があり、その場合には publishProgressから渡される複数の引数が、配列として渡されるためです。


import androidx.appcompat.app.AppCompatActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity{
    TextView txt;
    //============================================= onCreate
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        txt = findViewById(R.id.text1);

        //------------------------- 長い処理
        MyAsyncTask task =new MyAsyncTask(txt);
        task.execute();
    }
    //============================================= AsyncTask
    //<doInBackgroundの引数の型、onProgressUpdateの引数の型、doInBackgroundの戻り値の型>
    static class MyAsyncTask extends AsyncTask<Object, Integer, String>{
        TextView txt;
        MyAsyncTask(TextView txt) {
            super();
            this.txt = txt;
        }
        //============================================= 別スレッドで行う長い処理
        protected String doInBackground(Object[] objects) {
            try {
                for (int i=0; i<12; i++) {
                    publishProgress(new Integer(i));    //onProgressUpdate呼出
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {}
            return "終了しました";                      //この戻り値がonPostExecuteに渡される
        }
        //============================================= doInBackground終了後UIスレッド上で実行
        protected void onPostExecute(String str) {
            txt.setText(str);
        }
        //============================================= publishProgress呼出でUIスレッド上で実行
        protected void onProgressUpdate(Integer... values) {
            for(Integer i : values) {
                txt.setText(i+"秒");
            }
        }
    }
}

コメント

このブログの人気の投稿

ListViewの使い方

ListViewとSimpleAdapter使い方