【Andoid】AsyncTaskLoaderを使ってみる
Android 3.0から導入されたLoaderについて、
参考サイトをもとに勉強していましたがいまいちよくわからず。。
Loaderを継承した、AsyncTaskLoader
の方が使い方がわかりやすそうだったので、
まずはこちらを使用してみました。
Loaderの基本クラス
Loader
非同期のデータロードを行う為の抽象クラス。
LoaderManager
Loaderインスタンスを管理するためのクラス。
LoaderManagerインスタンスは、1つ以上のLoaderインスタンスを管理する。
Activityまたは、Fragmentごとに1つしか作られない。
LoaderManager.LoaderCallbacks
Activityまたは、FragmentとLoaderManager間で、
双方向にやりとりするためのコールバックインターフェース。
AsyncTaskLoaderを使ってみる
Activity側の実装
Activity側の実装では、Loaderを管理するLoaderManager
インスタンスを初期化する必要があります。
また、LoaderManagerから状態を受け取るためのコールバックとしてLoaderManager.LoaderCallbacks
インターフェースが用意されているため、Activityにこれを実装します。
LoaderManager
の初期化には、getLoaderManager().initLoader()
を使用します。
initLoader()
は、Activity.onStart()
よりも早く呼び出す必要があります。
引数について、以下のとおりです。
引数 | 詳細 |
---|---|
第一引数: int id |
Loaderの識別子。 onCreateLoader()第一引数に渡される。 |
第二引数: Bundle args |
Loaderへのパラメタ。 onCreateLoaderメソッドの第二引数に渡される。 Loaderがすでに生成されている場合は、この値は無視される。 |
第三引数: LoaderCallback callback |
Loaderの状態変化に使用される。 LoaderCallbackインターフェースを継承したクラスを指定する。 |
以下に、実装のサンプルを記載します。
// LoaderCallbacksのジェネリクスには、Loaderの戻り値の型を指定する(以下は、String) public class MainActivity extends Activity implements LoaderCallbacks<String> { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // LoaderManagerの初期化 getLoaderManager().initLoader(0, null, this); } @Override public Loader<String> onCreateLoader(int id, Bundle args) { // Loderを初期化する MyLoader loader = new MyLoader(this); return loader; } @Override public void onLoadFinished(Loader<String> loader, String data) { // dataでは、Loderクラスの戻り値が返される // Loderの終了処理 Log.d("","onLoadFinished"); } @Override public void onLoaderReset(Loader<String> arg0) { // Loderが、リセットされるときに呼ばれる。 // ここで、もらっているdataを破棄する必要がある。 Log.d("","onLoaderReset"); } }
Loaderの実装
非同期処理を行うLoaderクラスは、AsyncTaskLoader
クラスを継承して作成します。
Loaderが処理を開始するには、forceLoad()
を呼び出す必要があり、
以下のサンプルでは、Loderの準備が完了した際に呼ばれるonStartLoading()
で実行しています。
実際にバックグラウンドで行う処理は、loadInBackground()
に記載します。
public static class MyLoader extends AsyncTaskLoader<String> { public MyLoader(Context context) { super(context); } @Override public void deliverResult(String data) { // Loderが処理した結果を返す。(メインスレッドで実行される) super.deliverResult(data); } @Override public String loadInBackground() { // Loderが実行するバックグラウンド処理 return "abc"; } @Override protected void onStartLoading() { // Loder側の準備ができたタイミングで呼び出される // UIスレッドで実装される forceLoad(); } }
注意点
AsyncTaskLoaderを使う上で幾つか注意すべき点があります。
呼び出し元のActivityがアクティブでないと、
onLoadFinished()
コールバックが呼ばれないため、 それを考慮した実装を行う必要があります。Loaderインスタンスの
onStartLoading()
は、Activityがアクティブになったタイミングで呼ばれます。(何度も呼ばれる) その為、一度処理した内容が再度処理されないように意識した実装を行う必要があります。
※こちらを参考にしました。
これらを考慮したサンプルを以下に記載します。
public static class MyLoader extends AsyncTaskLoader<String> { private String data; public AsyncLoader(Context context) { super(context); } @Override public void deliverResult(D data) { if (isReset()) { return; } this.data = data; super.deliverResult(data); } @Override public String loadInBackground() { return "abc"; } @Override protected void onStartLoading() { if (data != null) { deliverResult(data); } if (takeContentChanged() || data == null) { forceLoad(); } } @Override protected void onStopLoading() { cancelLoad(); } @Override protected void onReset() { super.onReset(); onStopLoading(); data = null; } }
参考
http://www.techdoctranslator.com/android/guide/activities/loaders http://blog.loadlimits.info/2012/09/asynctaskloaderのあるactivityに戻ってきたときに再度loadinbackgroundが呼ば/ http://ijoru.com/ijoru/?p=207