AsyncTaskのサンプル
androidでサーバアクセスなど重めの処理を実行する場合にはAsyncTaskなどで非同期に行う。
このとき、ActivityとセットでAsyncTaskを書いたりする場合もあるが、そもそもActivityとAsyncTaskは生存期間が違う。
裏でAsyncTaskが動いているときに表でサクサクとActivityを切り替え、AsyncTaskが終わった時にたまたま動いていたActivityで何か処理をしたい場合もある。
そういう処理はServiceでやるべきという向きがあるかもしれないが、ひとまずAsyncTaskでやるならこんな感じではないかというのを晒してみる。
AsyncTask内でProgressDialogを出す場合も、この機構にonPauseのタイミングでdismissする部分を組み込むことで「View not attached to window manager」とか言われなくて済むようになるはず。
ApplicationにActivityのインスタンスを保持するのはご法度だが、onResumeで登録/onPauseで解除を自分でやってあげれば無問題。
当たり前っちゃあ、当たり前のコードではありますが。自分へのメモ的に。
- サンプルコード全体:AsyncSample.zip
- AsyncTaskが終わったことを通知してもらうインターフェース。Activityに実装させる。
package info.unknown_artifacts.example.asyncsample; public interface AsyncTaskCompleteListener { void onAsyncTaskComplete(AsyncTaskResult<?> result); }
- 上記リスナーを保持するインターフェース。AsyncTaskに実装させる。
package info.unknown_artifacts.example.asyncsample; public interface AsyncTaskNotifier { AsyncTaskCompleteListener getListener(); void setListener(AsyncTaskCompleteListener listener); }
- AsyncTaskが終わったときにリスナーに渡す情報。適当すぎるにもほどがある。
package info.unknown_artifacts.example.asyncsample; public class AsyncTaskResult<T> { private String id = null; private T val = null; public String getId() { return id; } public void setId(String id) { this.id = id; } public T getVal() { return val; } public void setVal(T val) { this.val = val; } }
- Application。AsyncTaskNotifier(実体はAsyncTask)を保持する。
package info.unknown_artifacts.example.asyncsample; import android.app.Application; public class SampleApplication extends Application { // 実際にはAsyncTaskNotifierホルダーもinterface化すべきだが手抜き private AsyncTaskNotifier task = null; public void setTask(AsyncTaskNotifier task) { this.task = task; } public void setAsyncTaskCompleteListener(AsyncTaskCompleteListener listener) { if (task != null) { task.setListener(listener); } } }
- サンプルのAsyncTask。
package info.unknown_artifacts.example.asyncsample; import android.os.AsyncTask; public class SampleAsyncTask extends AsyncTask<Long, Void, String> implements AsyncTaskNotifier { private AsyncTaskCompleteListener listener = null; public AsyncTaskCompleteListener getListener() { return listener; } public void setListener(AsyncTaskCompleteListener listener) { this.listener = listener; } @Override protected String doInBackground(Long... params) { try { // 時間のかかる処理だと思いねぇ。 Thread.sleep(params[0]); } catch (InterruptedException e) { /* N/A */ } return params[0].toString(); } @Override protected void onPostExecute(String val) { AsyncTaskResult<String> result = new AsyncTaskResult<String>(); result.setId(getClass().getName()); result.setVal(val); if (listener != null) { listener.onAsyncTaskComplete(result); } } public static void startSampleAsyncTask(SampleApplication app) { SampleAsyncTask task = new SampleAsyncTask(); app.setTask(task); task.execute(6000l); } }
- サンプルのActivity。Application経由でのAsyncTaskへの自身の登録/解除はもう少しきれいにした方がよさそう。
package info.unknown_artifacts.example.asyncsample; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class A01Activity extends Activity implements AsyncTaskCompleteListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.a01); ((Button) findViewById(R.id.btn_a02)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(A01Activity.this, A02Activity.class); startActivity(intent); } }); ((Button) findViewById(R.id.btn_start_task)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SampleApplication sampleApplication = (SampleApplication) getApplication(); SampleAsyncTask.startSampleAsyncTask(sampleApplication); sampleApplication.setAsyncTaskCompleteListener(A01Activity.this); } }); } @Override protected void onResume() { super.onResume(); ((SampleApplication) getApplication()).setAsyncTaskCompleteListener(this); } @Override protected void onPause() { super.onPause(); ((SampleApplication) getApplication()).setAsyncTaskCompleteListener(null); } @Override public void onAsyncTaskComplete(AsyncTaskResult<?> result) { ((SampleApplication) getApplication()).setTask(null); // 単一である場合は<String>決めうち、かつ、getIdの分岐は省いてよい if (result.getId().equals(SampleAsyncTask.class.getName())) { ((TextView) findViewById(R.id.lbl_message)).setText("[" + (String) result.getVal() + "]"); } } }