Android SDKのドキュメントには、startManagingCursor()
メソッドが廃止されたことが記載されています。
このメソッドは非推奨です。代わりに、LoaderManagerで新しいCursorLoaderクラスを使用してください。これは、古いプラットフォームでもAndroid互換性パッケージを介して利用できます。このメソッドにより、アクティビティは、アクティビティのライフサイクルに基づいて、指定されたCursorのライフサイクルを管理できます。停止すると、指定されたCursorでdeactivate()が自動的に呼び出され、後で再起動するとrequery()が呼び出されます。アクティビティが破棄されると、すべての管理対象カーソルが自動的に閉じられます。 、代わりにLoaderManagerを使用することを検討してください。これは、getLoaderManager()を介して利用できます
したがって、CursorLoader
を使用したいと思います。しかし、CursorAdapter
のコンストラクターでURIが必要な場合、カスタムContentProvider
を使用してCursorLoader
を使用せずに使用するにはどうすればよいですか。
コンテンツプロバイダーを必要としない simple CursorLoader を作成しました。
import Android.content.Context;
import Android.database.Cursor;
import Android.support.v4.content.AsyncTaskLoader;
/**
* Used to write apps that run on platforms prior to Android 3.0. When running
* on Android 3.0 or above, this implementation is still used; it does not try
* to switch to the framework's implementation. See the framework SDK
* documentation for a class overview.
*
* This was based on the CursorLoader class
*/
public abstract class SimpleCursorLoader extends AsyncTaskLoader<Cursor> {
private Cursor mCursor;
public SimpleCursorLoader(Context context) {
super(context);
}
/* Runs on a worker thread */
@Override
public abstract Cursor loadInBackground();
/* Runs on the UI thread */
@Override
public void deliverResult(Cursor cursor) {
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
/**
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
* will be called on the UI thread. If a previous load has been completed and is still valid
* the result may be passed to the callbacks immediately.
* <p/>
* Must be called from the UI thread
*/
@Override
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
/**
* Must be called from the UI thread
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
}
AsyncTaskLoader
クラスのみが必要です。 Android 3.0以降、または互換パッケージに付属しているもの)のいずれか。
私も ListLoader
と書きました はLoadManager
と互換性があり、汎用のJava.util.List
コレクション。
コンテンツプロバイダーの代わりにデータベースクラスを使用する独自のローダーを作成します。最も簡単な方法は、CursorLoader
クラスのソースを互換性ライブラリから取得し、プロバイダーのクエリを独自のdbヘルパークラスへのクエリに置き換えることです。
SimpleCursorLoaderはシンプルなソリューションですが、データが変更されたときにローダーを更新することはできません。 CommonsWareには、SQLiteCursorLoaderを追加し、データ変更の再クエリをサポートするloaderexライブラリがあります。
3番目のオプションは、単にloadInBackground
をオーバーライドすることです。
public class CustomCursorLoader extends CursorLoader {
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
@Override
public Cursor loadInBackground() {
Cursor cursor = ... // get your cursor from wherever you like
if (cursor != null) {
// Ensure the cursor window is filled
cursor.getCount();
cursor.registerContentObserver(mObserver);
}
return cursor;
}
};
これにより、データベースが変更されたときにカーソルを再クエリすることもできます。
唯一の警告:Googleは無限の知恵で彼らのパッケージを非公開にすることを決めたため、別のオブザーバーを定義する必要があります。元のクラス(または互換クラス)と同じパッケージにクラスを配置すると、実際には元のオブザーバーを使用できます。オブザーバーは非常に軽量なオブジェクトであり、他の場所では使用されないため、これは大きな違いをもたらしません。
Timo Ohrによって提案された3番目のオプションは、Yeungによるコメントとともに、最も簡単な答えを提供します(Occamのカミソリ)。以下は、私のために機能する完全なクラスの例です。このクラスを使用するには、2つのルールがあります。
基礎となるデータベースが変更されるたびに(たとえば、挿入または削除後)、必ず呼び出してください
getContentResolver().notifyChange(myUri, null);
ここで、myUriは、メソッドgetContentUri()の実装から返されたものと同じです。
私が使用したクラスのコードは次のとおりです。
package com.example.project;
import Android.content.Context;
import Android.database.Cursor;
import Android.content.CursorLoader;
import Android.content.Loader;
public abstract class AbstractCustomCursorLoader extends CursorLoader
{
private final Loader.ForceLoadContentObserver mObserver = new Loader.ForceLoadContentObserver();
public AbstractCustomCursorLoader(Context context)
{
super(context);
}
@Override
public Cursor loadInBackground()
{
Cursor cursor = getCursor();
if (cursor != null)
{
// Ensure the cursor window is filled
cursor.getCount();
cursor.registerContentObserver(mObserver);
}
cursor.setNotificationUri(getContext().getContentResolver(), getContentUri());
return cursor;
}
protected abstract Cursor getCursor();
protected abstract Uri getContentUri();
}