没有ContentProvider的CursorLoader用法
Android SDK文档说startManagingCursor()
方法是depraated:
此方法已弃用。 用LoaderManager代替新的CursorLoader类; 这也可以通过Android兼容性包在较老的平台上使用。 此方法允许活动根据活动的生命周期来pipe理给定游标的生命周期。 也就是说,当活动停止时,它会自动调用给定游标上的deactivate(),当它稍后重新启动时,它会为你调用requery()。 当活动被破坏时,所有被pipe理的游标将被自动closures。 如果您的目标是HONEYCOMB或更高版本,请考虑使用LoaderManager,而不是使用getLoaderManager()
所以我想用CursorLoader
。 但是当我需要CursorLoader
构造函数中的URI时,如何使用它与自定义的CursorAdapter
和没有ContentProvider
?
我写了一个简单的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或更高版本,也可以是兼容性软件包。
我还写了一个与LoadManager
兼容的LoadManager
,用于检索generics的java.util.List
集合。
编写你自己的装载器,使用你的数据库类而不是内容提供者。 最简单的方法就是从兼容性库中获取CursorLoader
类的源代码,并将提供者查询replace为您自己的db助手类的查询。
SimpleCursorLoader是一个简单的解决scheme,但不支持在数据更改时更新加载器。 CommonsWare有一个loaderex库,增加了一个SQLiteCursorLoader,并支持对数据更改的重新查询。
第三个选项是简单地覆盖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; } };
当数据库更改时,这也将负责重新查询游标。
只有警告:你必须定义另一个观察者,因为谷歌在无限的智慧决定使他们的包私人。 如果你把这个类放在原来的那个包(或者一个包)中,你可以使用原来的观察者。 观察者是一个非常轻量级的对象,并没有在其他地方使用,所以这并没有太大的区别。
Timo Ohr提出的第三个select,连同Yeung的意见,提供了最简单的答案(奥卡姆剃刀)。 下面是一个适合我的完整课程的例子。 有两个使用这个类的规则。
- 扩展这个抽象类并实现方法getCursor()和getContentUri()。
-
任何时候底层数据库发生变化(例如,在插入或删除之后),请确保调用
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(); }