AsyncTaskLoaderを利用した非同期処理を行う


Android3.0(HoneyComb)から、AndroidにはLoaderという非同期にデータをロードする仕組みが追加されています。
本エントリでは、そのLoaderの仕組みの中でもAsyncTaskに似た汎用的なLoaderのAsyncTaskLoaderの使い方を紹介しています。

以下スクリーンショットの様な、端末内のアプリケーション一覧を読み込むアプリケーションを作成し、
AsyncTaskLoaderを紹介していきます。

本サンプルは、Android Developersのサンプルを参考に処理を簡略化しています。
AsyncTaskLoaderを深く理解するために、リンク先も参考にするとよいと思います。

それでは続きをどうぞ。

AsyncTaskLoaderを利用する

はじめにAsyncTaskLoaderを利用する場合の重要なメソッドを以下に纏めます。
以下に挙げたメソッドはどれも必ず実装しなければならないものです。

LoaderCallbacksインターフェース

Loaderを呼び出すActivityやFragmentにimplementsするインターフェースです。

[table “199” not found /]

AsyncTaskLoaderクラスのメソッド

AsyncTaskLoaderクラスのメソッドとして、必ずOverrideし作成しなければならないメソッドは以下の一つです。

[table “200” not found /]

AsyncTaskLoaderを継承したクラスを用意する

早速、AsyncTaskLoaderを継承したクラスを用意しましょう。
AsyncTaskLoaderは抽象クラスのため、継承して利用します。
AsyncTaskLoaderを継承したクラスの作成方法の具体例は、以下サンプルをご覧下さい。

■ApplicationListLoader.java

public class ApplicationListLoader extends AsyncTaskLoader<List<ApplicationListItem>> {

    //省略.....

	@Override
	public List<ApplicationListItem> loadInBackground() {

    //省略.....
	}

作成するAsyncTaskLoaderを継承したクラスでは、バックグラウンドでの処理実行結果を返す型を指定する必要があります。
上記サンプルソースコードの1行目6行目に注目してください。
サンプルソースコードではList型がバックグラウンドでの実行結果の戻りになっていることがわかります。

バックグラウンド処理を記述する

作成したAsyncTaskLoaderを継承したクラスのloadInBackgroundメソッド内にバックグラウンドで実行する処理を記述します。
loadInBackgroundメソッドの実行後、Activity/Fragmentに実装するonLoadFinishedメソッドが呼び出されます。
onLoadFinishedメソッドでAsyncTaskLoaderの実行結果を利用する場合には、loadInBackgroundメソッドのreturnに指定しましょう。
onLoadFinishedメソッドの第二引き数として取得することができます。

本サンプルでは、バックグラウンドで端末にインストールされたアプリケーション一覧を取得しています。
該当の処理は以前にTechBoosterで紹介した内容でもありますので、詳細はそちらを確認ください。

インストール済みアプリケーションのアプリケーション名とアイコンを取得する
リストビューをカスタマイズする

loadInBackgroundメソッドの処理は以下の通りです。
前述の通り、アプリケーションの一覧をPackageManagerから取得し、
Listアイテムの管理用に作成したApplicationListItemクラスに挿入しています。

■ApplicationListLoader.java

	@Override
	public List<ApplicationListItem> loadInBackground() {
		// Application一覧の取得
		List<ApplicationInfo> appInfoList = pm.getInstalledApplications(Context.BIND_AUTO_CREATE);

		// Application一覧の読み込み
		List<ApplicationListItem> ret = new ArrayList<ApplicationListItem>(appInfoList.size());
		for(ApplicationInfo info : appInfoList){
			ApplicationListItem item = new ApplicationListItem(info);
			try {
				// nameの追加
				item.setName(info.loadLabel(pm).toString());

				// Iconの追加
				item.setIcon(pm.getApplicationIcon(info.packageName));
			} catch (NameNotFoundException e) {
				e.printStackTrace();
			}
			ret.add(item);
		}
		return ret;
	}

2行目でloadInBackgroundメソッドの戻り値を指定しています。
ここで、onLoadFinishedメソッドで利用する型を宣言しておきましょう。
本サンプルでは、インストールされたアプリケーションをリスト表示するためのList型をreturnしています。

Loaderを呼び出す

Activity、またはFragmentからLoaderを呼び出す事ができます。
Loaderを呼び出すActivity/Fragmentには、LoaderCallbacksインターフェースimplementsする必要があります。
実装しなければならないメソッドは冒頭の表でも触れた通り、onCreateLoaderメソッドonLoadFinishedメソッドonLoaderResetメソッドの3つです。

サンプルでの3つのメソッドの実装は以下の通りになっています。

■LoaderSampleActivity.java

public class LoaderSampleActivity extends Activity implements LoaderCallbacks<List<ApplicationListItem>>{
	ApplicationListAdapter mAdapter;

	// 省略...(下記にて別途引用)
	// onCreateメソッド

    /**
     * Loaderの開始処理
     */
	@Override
	public Loader<List<ApplicationListItem>> onCreateLoader(int id, Bundle args) {
		ApplicationListLoader appLoader = new ApplicationListLoader(getApplication());

		// loaderの開始
		appLoader.forceLoad();
		return appLoader;
	}

	/**
	 * Loaderの処理終了コールバック
	 */
	@Override
	public void onLoadFinished(Loader<List<ApplicationListItem>> arg0,
			List<ApplicationListItem> arg1) {
		// リスト表示するAdapterにアイテムをセット
		for(ApplicationListItem item : arg1){
			mAdapter.add(item);
		}

		// リスト表示の更新
		mAdapter.notifyDataSetChanged();
	}

	/**
	 * Loaderがリセットされた時によびだされる
	 */
	@Override
	public void onLoaderReset(Loader<List<ApplicationListItem>> arg0) {
          // 今回は無視する
	}

11行目、23行目、38行目でそれぞれLoaderCallbacksインターフェースのメソッドをOverrideしています。
15行目でLoaderクラスのforceLoadメソッドを呼び出し、Loaderの処理を開始させています。
forceLoadメソッドの呼び出しはプロセスのメインスレッドで行う必要があります。

また、Callbackメソッドを用意する以外にLoaderの初期化処理を行う必要があります。
初期化処理はLoaderManagerクラスのinitLoaderメソッドを利用して行います。
Loaderの初期化処理のサンプルは以下の通りです。

■LoaderSampleActivity.java

   @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ListView list = (ListView)findViewById(R.id.listView1);
        mAdapter = new ApplicationListAdapter(this, android.R.layout.simple_list_item_1);
        list.setAdapter(mAdapter);

        // loaderの初期化
        getLoaderManager().initLoader(0, null, this);
    }

11行目でLoaderの初期化処理を行っています。
ActivityクラスのgetLoaderManagerメソッドでLoaderManagerクラスのインスタンスを取得し、initLoaderメソッドを呼び出しています。
initLoaderクラスのメソッドの引数は、次のとおりになります。

[table “202” not found /]