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で解除を自分でやってあげれば無問題。

当たり前っちゃあ、当たり前のコードではありますが。自分へのメモ的に。

  • 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() + "]");
		}
	}
}