ページ

2013/04/27

[Android]AsyncTaskLoaderを簡単に扱えるAbstractAsyncLoader

AsyncTaskLoader って AsyncTask を並列実行できるだけのやつでしょ、
なんだかよくわからないし FragmentActivity 使わないといけないしで敬遠していたけど
カメラプレビュー連射して保存を Thread で並列実行したら余裕で OOM が出るので
使うことにしました。
Fragment のライフサイクルや AsyncTaskLoader の処理の流れも知らなかったので
AsyncTaskLoader | Android Developersのサンプルコードを読んでみるも
Web でのソースコードを読むのが辛く、関係ない処理も含まれている感じで
よくわかりませんでした。

ということでいくつかのページを参考に AsyncTaskLoader を理解していきました。
AsyncTaskLoaderを使ってみる | Developers.IO
主に動作イメージなんかがわかりやすかったです。
AsyncTaskLoaderに手を出してみる - ナカザンドットネット
ソースコードのコメントが簡潔でわかりやすかったです。
技術見聞録 - AsyncTaskLoaderの動作をソースから知る
AsyncTaskLoader の挙動がちょっとわかるかもしれません。
LoaderManager#enableDebugLogging(boolean) | Android Developersというものがあるらしいです。
AsyncTaskLoaderのあるActivityに戻ってきたときに再度loadInBackgroundが呼ばれる問題 - digital matter
ココからリンクされている以下の Stack Overflow にたどり着くことができたページ。
android - onLoadFinished not called after coming back from a HOME button press - Stack Overflow
神、いわゆるゴッド。
さすが Stack Overflow 神!俺達にできないことを平然とやってのける!そこにシビれる!あこがれるゥ!
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;

public abstract class AbstractAsyncLoader<D> extends AsyncTaskLoader<D> {

    private D mData = null;

    public AbstractAsyncLoader(Context context) {
        super(context);
    }

    /**
     * {@link #startLoading()}が呼び出された時に呼び出される。
     * データが有る場合は結果を送り、ない場合は新規のデータをロードする。
     * 
     * @UiThread
     */
    @Override
    protected void onStartLoading(){
        // すでにデータが有る場合は結果を送る
        if(mData != null){
            deliverResult(mData);
        }
        // loader停止中にコンテンツが変わった、またはデータがない
        if(takeContentChanged() || mData == null){
            // #startLoading()とは異なり、以前のデータを無視して新規のデータをロードする
            forceLoad();
        }
    }

    /**
     * 非同期処理を行い、その結果を返す。
     * 
     * @Background
     */
    @Override
    public D loadInBackground(){
        return mData;
    }

    /**
     * {@link #stopLoading()}が呼び出された時に呼び出される。ロードをキャンセルする。
     * 
     * @UiThread
     */
    @Override
    protected void onStopLoading(){
        // 可能な場合、ロードをキャンセルする
        cancelLoad();
    }

    /**
     * {@link #reset()}が呼び出された時に呼び出される。ロードをキャンセルし、データを破棄する。
     * 
     * @UiThread
     */
    @Override
    protected void onReset(){
        super.onReset();
        stopLoading();
        mData = null;
    }

    /**
     * onLoadCompleteリスナーに結果を送る。
     * メインスレッドから呼び出す。
     * 
     * @param 結果
     */
    @Override
    public void deliverResult(D data){
        if(isReset()){
            // Loader停止中に呼び出された
            return;
        }
        mData = data;
        super.deliverResult(data);
    }

}
まだちょっとしか使ってないから適切かどうか自信がないけど
だいたいこんな感じで処理を組めば良いという目安にしておきたいと思う。

ジョジョの奇妙な冒険 Vol.1 (第1部オリジナルサウンドトラック、全巻購入特典フィギュア応募券付き)(初回限定版) [Blu-ray]
ジョジョの奇妙な冒険 Vol.1 (第1部オリジナルサウンドトラック、全巻購入特典フィギュア応募券付き)(初回限定版) [Blu-ray]