私はアプリでCursors
を広範囲に使用して、データベースとの間で情報を読み込んだり、場合によっては書き込んだりしています。 HoneycombとCompatibilityPackageには、「適切な」方法でデータをロードするのに役立つように設計された新しいLoader
クラスがあることを確認しました。
基本的に、これらの新しいクラス(特にCursorLoader
)は、データを管理する以前の方法よりもかなり優れていますか?たとえば、管理されたCursorLoader
に対するCursors
の利点は何ですか?
そして、私はContentProvider
を使用してデータを処理します。これには、明らかにUris
が必要ですが、これはinitLoader()
メソッドとどのように連携しますか?ローダーを個別に使用するには、各Fragments
を設定する必要がありますか?また、IDはローダーごとにどの程度一意である必要がありますか?それは私のアプリの範囲を超えていますか、それとも単なるフラグメントですか? Uri
をCursorLoaderに渡してデータをクエリする簡単な方法はありますか?
現時点で私が見ることができるのは、ローダーが私のデータをアプリに取り込むために不要な余分なステップを追加することだけです。誰かが私にそれらをよりよく説明できますか?
アプリでActivity.managedQuery()
よりもCursorLoader
を使用することには2つの重要な利点があります。
AsyncTaskLoader
で構築されているため)、大きなデータクエリがUIをブロックすることはありません。これは、プレーンなCursor
を使用するときにドキュメントで推奨されていることですが、現在は内部で実行されています。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
お役に立てば幸いです。
誰かが同じような状況に陥った場合、私がしたことは次のとおりです。
LoaderCallbacks
を実装し、必要なクエリをすべて処理するクラスを作成しました。Context
と問題のAdapter
を提供します。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;
}
_
これが他の誰かに役立つことを願っています:)
[〜#〜]編集[〜#〜]
より完全に説明するには:
Cursor
を持つアダプターが初期化されます。 Cursor
はアダプタにonLoadFinished(..)
の正しいGlobalCallbacks
を与えるため、Cursor
は提供しません。LoaderManager
に新しいCursorLoader
を初期化するように指示します。新しいGlobalCallbacks
インスタンス(_Loader.Callbacks
_を実装)を提供し、カーソルの読み込みを監視します。アダプターも提供する必要があるため、ロードが完了すると、新しいCursor
にスワップできます。ある時点で、(OSに組み込まれている)LoaderManager
はGlobalCallbacks
のonCreateLoader(..)
を呼び出し、データの非同期ロードを開始しますHelper.bundleArgs(..)
はクエリの引数をBundle
に入れるだけです(例:列の射影、並べ替え順序、WHERE句)Fragment
のListAdapter
を設定します。この時点ではカーソルはまだnullであるため、onLoadFinished()
が呼び出されるまで、読み込み記号または空のメッセージが表示されます。