web-dev-qa-db-ja.com

CursorLoadersの利点は何ですか?

私はアプリでCursorsを広範囲に使用して、データベースとの間で情報を読み込んだり、場合によっては書き込んだりしています。 HoneycombとCompatibilityPackageには、「適切な」方法でデータをロードするのに役立つように設計された新しいLoaderクラスがあることを確認しました。

基本的に、これらの新しいクラス(特にCursorLoader)は、データを管理する以前の方法よりもかなり優れていますか?たとえば、管理されたCursorLoaderに対するCursorsの利点は何ですか?

そして、私はContentProviderを使用してデータを処理します。これには、明らかにUrisが必要ですが、これはinitLoader()メソッドとどのように連携しますか?ローダーを個別に使用するには、各Fragmentsを設定する必要がありますか?また、IDはローダーごとにどの程度一意である必要がありますか?それは私のアプリの範囲を超えていますか、それとも単なるフラグメントですか? UriをCursorLoaderに渡してデータをクエリする簡単な方法はありますか?

現時点で私が見ることができるのは、ローダーが私のデータをアプリに取り込むために不要な余分なステップを追加することだけです。誰かが私にそれらをよりよく説明できますか?

25
Alex Curran

アプリでActivity.managedQuery()よりもCursorLoaderを使用することには2つの重要な利点があります。

  1. クエリはバックグラウンドスレッドで処理されるため(AsyncTaskLoaderで構築されているため)、大きなデータクエリがUIをブロックすることはありません。これは、プレーンなCursorを使用するときにドキュメントで推奨されていることですが、現在は内部で実行されています。
  2. CursorLoaderは自動更新されます。 CursorLoaderは、最初のクエリの実行に加えて、要求したデータセットにContentObserverを登録し、データセットが変更されたときにそれ自体でforceLoad()を呼び出します。これにより、ビューを更新するためにデータが変更されるたびに非同期コールバックが取得されます。

Loaderインスタンスも単一のLoaderManagerを介して処理されるため、カーソルを直接管理する必要はなく、単一のActivityを超えても接続を維持できるようになりました。 。 LoaderManager.initLoader()およびLoaderManager.restartLoader()を使用すると、クエリ用にすでに設定されている既存のLoaderに再接続でき、場合によっては、最新のデータが利用可能な場合は即座に取得できます。

ActivityまたはFragmentは、おそらく_LoaderManager.Callback_インターフェースを実装します。 initLoader()を呼び出すと、onCreateLoader()メソッドが生成され、必要に応じてクエリと新しいCursorLoaderインスタンスが作成されます。 onLoadFinished()メソッドは、新しいデータが利用可能になるたびに起動され、ビューにアタッチしたり、繰り返し処理したりするための最新のCursorが含まれます。

さらに、LoaderManagerクラスのドキュメントページに、このすべての適合のかなり良い例があります: http://developer.Android.com/reference/Android/app/LoaderManager.html

お役に立てば幸いです。

44
Devunwired

誰かが同じような状況に陥った場合、私がしたことは次のとおりです。

  • LoaderCallbacksを実装し、必要なクエリをすべて処理するクラスを作成しました。
  • これにContextと問題のAdapterを提供します。
  • 使用するクエリごとに一意のIDを作成します(UriMatcherを使用する場合は、同じIDを使用することもできます)
  • LoaderCallbacksに必要なバンドルにクエリを転送する便利なメソッドを作成します
  • それはほとんどそれです:)私がしたことを正確に示すために私は以下に私のコードのいくつかを置きました

私のGlobalCallbacksクラスでは:

_public static final String PROJECTION = "projection";
public static final String SELECTION = "select";
public static final String SELECTARGS = "sargs";
public static final String SORT = "sort";

Context mContext;
SimpleCursorAdapter mAdapter;

public GlobalCallbacks(Context context, SimpleCursorAdapter adapter) {
    mContext = context;
    mAdapter = adapter;
}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    Uri contentUri = AbsProvider.customIntMatch(id);
    if (contentUri != null) {
        return new CursorLoader(mContext, contentUri, args.getStringArray(PROJECTION), args.getString(SELECTION), 
                args.getStringArray(SELECTARGS), args.getString(SORT));
    } else return null;

}

@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {
    mAdapter.swapCursor(arg1);      
}

@Override
public void onLoaderReset(Loader<Cursor> arg0) {
    mAdapter.swapCursor(null);
}
_

そして、CursorLoaderを使用したい場合(Helper.bundleArgs()は便利なバンドル方法です):

_scAdapt = new Adapters.NewIndexedAdapter(mHost, getMenuType(), 
                null, new String[] { "name" }, new int[] { Android.R.id.text1 });
        getLoaderManager().initLoader(
                GlobalCallbacks.GROUP,
                Helper.bundleArgs(new String[] { "_id", "name" }),
                new GlobalCallbacks(mHost, scAdapt));
        setListAdapter(scAdapt);
_

そしてヘルパーで:

_public static Bundle bundleArgs(String[] projection, String selection, String[] selectionArgs) {
    Bundle b = new Bundle();
    b.putStringArray(GlobalCallbacks.PROJECTION, projection);
    b.putString(GlobalCallbacks.SELECTION, selection);
    b.putStringArray(GlobalCallbacks.SELECTARGS, selectionArgs);
    return b;
}
_

これが他の誰かに役立つことを願っています:)

[〜#〜]編集[〜#〜]

より完全に説明するには:

  • 最初に、null Cursorを持つアダプターが初期化されます。 CursorはアダプタにonLoadFinished(..)の正しいGlobalCallbacksを与えるため、Cursorは提供しません。
  • 次に、LoaderManagerに新しいCursorLoaderを初期化するように指示します。新しいGlobalCallbacksインスタンス(_Loader.Callbacks_を実装)を提供し、カーソルの読み込みを監視します。アダプターも提供する必要があるため、ロードが完了すると、新しいCursorにスワップできます。ある時点で、(OSに組み込まれている)LoaderManagerGlobalCallbacksonCreateLoader(..)を呼び出し、データの非同期ロードを開始します
  • Helper.bundleArgs(..)はクエリの引数をBundleに入れるだけです(例:列の射影、並べ替え順序、WHERE句)
  • 次に、FragmentListAdapterを設定します。この時点ではカーソルはまだnullであるため、onLoadFinished()が呼び出されるまで、読み込み記号または空のメッセージが表示されます。
10
Alex Curran