AsyncTaskLoader の使い方 (1/8) 〜 Thread と AsyncTask

もう非同期処理では、あたりまえなのだろうが、まとめておかないとすぐに忘れる。

AsyncTaskLoader___Android_Developers

AsyncTaskLoader | Android Developers


目次

1. Thread と AsyncTask
2. AsyncTaskLoader の利点
3. LoaderManager の利用
4. よくある間違いと回避法
5. 基本的な Loader の実装
6. いろいろな Loader の使用例
7. データベースと CursorLoader
8. Loader の弱点を克服する


1. Thread と AsyncTask

まずは、非同期処理ではおなじみのThread。

final Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch(msg.what) {
case RESULT_WHAT:
handleResult((Result) msg.obj);
return true;
}
return false;
}
});
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Result result = doStuff();
if (isResumed()) {
handler.sendMessage(handler.obtainMessage(RESULT_WHAT, result));
}
}
});
thread.start();

めんどくさいことがいくつかある。

  • メインスレッドに結果を戻す必要がある。
  • 手動でキャンセルしなければならない。
  • スレッドをプールしたければ独自実装しなければならない。

でそこらに対応した AsyncTask。以下の特徴をもつ。

  • 結果をメインスレッドに送ってくれる。
  • スケジュールは管理されている。
  • キャンセル処理も可能。
  • 進行状況が取得できる。

private class DownloadFilesTask extends AsyncTask<Void, Integer, Result> {
@Override
protected void onPreExecute() {
// Something like showing a progress bar
}
@Override
protected Result doInBackground(Void... params) {
Result result = new Result();
for (int i = 0; i < STEPS; i++) {
result.add(doStuff());
publishProgress(100 * i / STEPS);
}
return result;
}
@Override
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
@Override
protected void onPostExecute(Result result) {
handleResult(result);
}
}

これの問題点。

アクティビティがdestroyedしたときでもキャンセルできるようにそれぞれのAsyncTaskの参照を保持しておく必要がある。

メモリーリーク: エンクロージングActivityがdestoryされても、AsyncTaskが実行されている間は、そのActivityに参照を保持している。

結果が返却されたあと、Activityが再作成(orientation change)されるとその結果が失われる。

AsyncTaskのスケジューリングは Androidのバージョンによって異なる。

/*
1.6 以前は、シングルスレッドで順番に実行される
1.6 から 2.3、スレッドプールで並列に実行される。
3.0 以降、デフォルトで以前の動作に戻る。スレッドプール利用はexecuteOnExecutor()で。
今どきの端末ではデフォルトでは並列実行されない。
*/
public class ConcurrentAsyncTask {
public static void execute(AsyncTask as) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
as.execute();
} else {
as.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}

そして、今どきは AsyncTaskLoader。

(→ 「2.AsyncTaskLoader の利点」につづく )


関連ワード:  Android今さら聞けない開発