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+"秒");
}
}
}
}
コメント
コメントを投稿