2012年7月5日木曜日

[Android][Fragment][Loader][ArrayAdapter]ListFragmentにLoaderを使ってArrayAdapterからリストを表示する

ListFragmentにデータを表示する際、単純にリストのデータを表示したい場合は、ArrayAdapterを使って表示すると思いますが、データが大量にある場合にはやっぱりバックグラウンドでやるべきですよね。

最近はバックグラウンドでの読み込みはLoaderを使ってやるのが良いみたいなのでLoaderを使ってみました。




データをCursorから読み込み場合にはCursorLoaderというクラスがあって簡単に実装できるのですが、Listから読み込むにはAsyncTaskLoaderで独自のLoaderを作成する必要があります。

とうわけでコードです。

まずはLoader。

import java.util.List;

import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;

public class MyLoader extends AsyncTaskLoader<List<String>> {
 
    private List<String> mStrings;
    
    /**
     * コンストラクタ
     * @param context 親クラスのコンテキスト
     */
    public MyLoader(Context context) {
        super(context);
    }

    @Override
    public List<String> loadInBackground() {
        // ここでArrayAdapterに渡すためのデータを作って返す
        List<String> strings;
        return strings;
    }
    
    /**
     * 提供する新しいデータがある場合に呼び出される
     */
    @Override
    public void deliverResult(List<String> strings) {
        if(isReset()){
            // リセット時
            return;
        }
        mRecords = records;
        if(isStarted()) {
            // データの読込中
            super.deliverResult(strings);
        }
    }
    
    /**
     * ローダーの開始
     */
    @Override
    protected void onStartLoading() {
        if(mRecords != null){
            // データが取得済みの場合それを返す
            deliverResult(mStrings);
        } else {
            // 取得できていない場合読み込む
            forceLoad();
        }
    }
    
    /**
     * ローダーの停止
     */
    @Override
    protected void onStopLoading() {
        cancelLoad();
    }
    
    /**
     * キャンセル処理
     */
    @Override
    public void onCanceled(List<String> strings) {
        super.onCanceled(strings);
    }
    
    /**
     * ローダーのリセット
     */
    @Override
    protected void onReset() {
        super.onReset();
        onStopLoading();
        if (mStrings != null) {
            mStrings = null;
        }
    }
}
次に、Loaderを生成するListFragmentです。
import java.util.List;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;

public class LatestRecordFragment extends ListFragment implements LoaderCallbacks<List<String>> {

    /** アダプター */
    private MyArrayAdapter mAdapter;

    /** ローダー */
    private MyLoader mLoader;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        setEmptyText(getText(R.string.msg_no_record));
        mAdapter = new MyArrayAdapter(getActivity());
        setListAdapter(mAdapter);

        setListShown(false);

        LoaderManager manager = getLoaderManager();
        manager.initLoader(0, null, this);

    }

    @Override
    public Loader<List<String>> onCreateLoader(int id, Bundle args) {
        mLoader = new MyLoader(getActivity());
        return mLoader;
    }

    @Override
    public void onLoadFinished(Loader<List<String>> loader, List<String> data) {
        mAdapter.setData(data);
        if (isResumed()) {
            // リストを表示
            setListShown(true);
        } else {
            // 一時停止時はアニメーションなしで表示
            setListShownNoAnimation(true);
        }
    }

    @Override
    public void onLoaderReset(Loader<List<String>> arg0) {
        mAdapter.setData(null);
    }

    /**
     * ローダーを再読み込みするためのメソッド
  */
    public void loderContentChanged() {
        mLoader.onContentChanged();
    }
}
ArrayAdapterの実装は大したことないので割愛します。 

Loader使うと画面回転時にも自動でデータの再読み込みしてくれるみたいですし、ちょっと面倒でもLoaderを使うようにしたほうがよさそうですね。

 ちなみに参考にしたのは、こちらのAndroid UI Cookbook for 4.0 ICSです。
 FragmentやLoaderなどの2.3以降に追加された機能に関しての内容が盛り沢山でとても参考になります。 電子書籍版も発売されてますしオススメですよー。

0 件のコメント:

コメントを投稿