Android 開発でユーザービリティを向上させるのに良く利用する AsyncTask ですが、cancel した時の内部の動作が不明だったので調べまてみました。 知りたいのは、 「cancel を呼び出したら、doInBackgroud で行われている処理はどうなるのか?」 です。

そこで用意したのが下のプログラムです。 これはクラス変数 count を MyTask によって 100 まで加算します。 MyTask のインスタンスを二つ用意し、

  1. タスクAを開始
  2. 5秒待つ
  3. タスクAをキャンセル
  4. タスクBを開始

という処理をしています。 タスク A と B で count は共有しています。

AsyncTask のテストプログラム1

```java
public class AsyncTestActivity extends Activity {
private int count = 0;
private MyTask task = null;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button btn = (Button)findViewById(R.id.Button01);
    btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View view) {

            // タスク A を実行
            task = new MyTask("taskA");
            task.execute((Void)null);

            // 5秒待つ
            SystemClock.sleep(5000);

            // タスク A を中断
            task.cancel(true);

            // タスク B を実行
            task = new MyTask("taskB");
            task.execute((Void)null);
        }
    });
}

/** 非同期で加算を行う内部クラス */
class MyTask extends AsyncTask {
    private String name = "";

    MyTask(String name) {
        this.name = name;
    }

    /** 非同期処理 */
    @Override
    protected Long doInBackground(Void... params) {
        long start = System.currentTimeMillis();

        // count を 0~100 まで 100ms 毎に加算する処理
        count = 0;
        for (int i = 0; i < 100; i++) {
            SystemClock.sleep(100);
            count++;
        }

        // 処理にかかった時間を返す
        return System.currentTimeMillis() - start;
    }

    /** doInBackground が終わったら呼び出される。 */
    @Override
    protected void onPostExecute(Long result) {
        // 結果を表示 "タスク名 - カウンタ値 - 処理時間ms"
        Toast.makeText(AsyncTestActivity.this,
            name + " - " + String.valueOf(count) + " - " 
                        + String.valueOf(result) + "ms",
            Toast.LENGTH_LONG).show();
    }
} }

まず前提として、タスクを1つだけ実行した時は、こんな結果になります。

###タスク A だけを実行した時の結果

taskA - 100 - 100029ms

100ミリ秒毎に100回加算しているので、妥当な結果といえます。

このコードを実行すると次のような結果になりました。

テストプログラム1の結果

taskB - 151 - 100031ms

taskA の結果は出力されないので cancel した場合は onPostExecute は呼び出されない事が分かります。

しかし、カウント値が 151 と異常になってます。 どうやら taskA と taskB が並列処理されてしまっているようです。 なので、cancel を呼び出しても、doInBackground の処理は継続して行われている事が分かります。

今回分かったことは

  • AsyncTask.cancel を呼ぶと、onPostExecute は呼び出されない。
  • AsyncTask.cancel を呼んだだけでは doInBackground の処理は中断されない。
    です。

じゃあ、どうやって中断させようか、という事で次回↓へ続く。

AsyncTask を cancel した時の動き【その2】

Android
Java

published

Ads

Read more!

amay077

Microsoft MVP(Xamarin). フルリモートワーカー. Geospatial Mobile app developer. Love C#.

amay077 amay077