データベース問い合わせ等の比較的重たい処理を、UI threadに負荷を与えずに行いたい場合、AsyncTaskクラスを利用します。
AsyncTaskクラスは別スレッドでのバックグラウンド処理と、処理前と処理後のUI threadへのコールバックの2つを提供してくれる、便利なクラスです。
AsyncTaskを利用するには、AsyncTaskのサブクラスを実装する必要があります。
サンプルとして、GeoCoderを使った簡易住所検索アプリを作成しながら、AsyncTaskの使用方法を解説します。
Activityの作成
新規Androidプロジェクトを作成し、タスク実行を行うAddressRequestActivityを作成します。
AddressRequestActivityでは、Button押下時にEditTextに入力された文字列を元にAddressを取得しTextViewに表示をします。
address_request.xml
AddressRequestActivity.java
Taskの実装
「Address取得→データの整形→表示」までの処理を、AddressRequestTaskクラスを作成し、実装します。
AsyncTaskのサブクラスでは、実行時引数(Param)、進捗単位(Progress)、処理結果(Result)で扱う型を指定する必要があります。
AddressRequestTaskの場合は、実行時引数(String)、進捗単位(Integer)、処理結果(Address)を扱います。
public class AddressRequestTask extends AsyncTask<String, Integer, Address>
doInBackground()を実装し、必要に応じてonPreExecute()やonPostExecute()を実装します。
@Override
protected void onPreExecute() { // …①
mResultText.setText(null);
mProgressDialog = new ProgressDialog(mActivity);
mProgressDialog.setTitle("In Processing...");
mProgressDialog.setIndeterminate(true);
mProgressDialog.show();
}
@Override
protected Address doInBackground(String... locationNames) { // …②
Address result = null;
try {
List<Address> results = mGeocoder.getFromLocationName(locationNames[0], 1);
if (results != null && !results.isEmpty()) {
result = results.get(0);
}
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
return result;
}
@Override
protected void onPostExecute(Address result) { // …③
mProgressDialog.dismiss();
if (result != null) {
double latitude = result.getLatitude();
double longitude = result.getLongitude();
StringBuilder builder = new StringBuilder();
builder.append("latitude:").append(String.valueOf(latitude)).append("\n");
builder.append("longitude:").append(String.valueOf(longitude));
mResultText.setText(builder.toString());
} else {
Toast toast = Toast.makeText(mActivity, "Not Found.", Toast.LENGTH_LONG);
toast.show();
}
}
AddressRequestTaskでは
①onPreExecute()で進捗ダイアログの表示を行い、
②doInBackground()でGeoCoderへの問い合わせ→Address取得、
③onPostExecute()でデータの整形→表示と、進捗ダイアログの非表示を行っています。
doInBackground()内でUI threadに関わる処理を記述すると、実行時にエラーとなるので注意が必要です。
ダイアログの表示/非表示や取得データの表示といった、画面の描画を伴うような処理はdoInBackground()に記述せずに、
onPreExecute()やonPostExecute()に記述する必要があります。
タスクを実行するにはexecute()メソッドを呼びます。
AddressRequestActivityのボタン押下時に、入力値の取得とタスクの実行を実装しています。
String locationName = mLocationNameEdit.getText().toString(); AddressRequestTask task = new AddressRequestTask(this); task.execute(locationName);
進捗ダイアログの更新
サンプルのProgressDialogにはsetIndeterminate()にtrueを設定し無限に表示を続けるよう指定していますが、
doInBackground()内での処理の進み具合に応じてダイアログを更新したい場合、publishProgress()メソッドを使います。
publishProgress()はAsyncTaskの実行時同様、コールバックを自分自身に設定したMessageをHandlerへPostし、
バックグラウンド処理からダイアログを更新するUI threadへのアクセスを実現しています。
publishProgress()への引数は、進捗単位(Progress)に指定した型を用います。
Integer progress = 10; publishProgress(progress);
publishProgress()メソッドが処理されると、そのコールバックとしてonProgressUpdate()メソッドが呼ばれます。
引数の値は、publishProgress()で指定した値が入ります。
@Override
protected void onProgressUpdate(Integer... progress) {
mProgressDialog.setProgress(progress[0]);
}
