AsyncTaskでバックグラウンド処理を行う

Last-modified: 2009-09-09 (水) 10:58:41

データベース問い合わせ等の比較的重たい処理を、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クラスを作成し、実装します。

 

AddressRequestTask.java

 

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]);
}