25

Cursors在我的应用程序中广泛使用,以加载和偶尔从数据库写入信息。我已经看到 Honeycomb 和 Compatibility Package 具有Loader旨在帮助以“良好”方式加载数据的新类。

从本质上讲,这些新类(尤其是CursorLoader)是否比以前的数据管理方法好很多?例如,CursorLoader过度管理有什么好处?Cursors

我使用 aContentProvider来处理数据,这显然需要,Uris但是这与initLoader()方法有何关系?我必须设置每个Fragments单独使用加载器吗?每个加载器的 id 需要有多独特,它是在我的应用程序的范围内还是只是一个片段?是否有任何简单的方法可以简单地将 a 传递Uri给 CursorLoader 来查询我的数据?

目前我所能看到的是加载器添加了一个不必要的额外步骤来将我的数据导入我的应用程序,所以有人可以更好地向我解释一下吗?

4

2 回答 2

44

CursorLoader在您的应用程序中使用 a 有两个主要好处Activity.managedQuery()

  1. 查询在后台线程上为您处理(由 bu​​ild on 提供AsyncTaskLoader),因此大型数据查询不会阻塞 UI。这是文档建议您在使用 plain 时为自己做的事情Cursor,但现在它已经在幕后完成了。
  2. CursorLoader正在自动更新。除了执行初始查询之外,它还向您请求的数据集CursorLoader注册 aContentObserverforceLoad()在数据集更改时调用自身。这会导致您在数据更改时获得异步回调以更新视图。

每个Loader实例也通过单数处理LoaderManager,因此您仍然不必直接管理游标,现在连接甚至可以持续超过单个Activity. LoaderManager.initLoader()LoaderManager.restartLoader()允许您重新连接Loader已为您的查询设置的现有数据,并且在某些情况下,如果可用,可以立即获取最新数据。

ActivityFragment现在可能会实现该LoaderManager.Callback接口。如有必要,调用initLoader()将导致onCreateLoader()您将在其中构造查询和新CursorLoader实例的方法。onLoadFinished()每次有新数据可用时都会触发该方法,并将包括最新的数据Cursor以供您附加到视图或以其他方式迭代。

LoaderManager此外,在类文档页面 上有一个很好的例子来说明所有这些内容:http: //developer.android.com/reference/android/app/LoaderManager.html

于 2011-08-24T22:48:55.387 回答
10

如果有人发现自己处于类似情况,这就是我所做的:

  • 创建了一个实现LoaderCallbacks和处理您需要的所有查询的类。
  • 提供这个和有Context问题的Adapter
  • 为您将使用的每个查询创建唯一 ID(如果您使用 a 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首先,初始化一个带有 null 的适配器。我们不提供它,Cursor因为它GlobalCallbacks会为适配器提供正确CursoronLoadFinished(..)
  • 接下来,我们告诉LoaderManager我们要初始化一个新的CursorLoader. 我们提供了一个新GlobalCallbacks实例(它实现了Loader.Callbacks),然后它将监视游标的加载。我们还必须为它提供适配器,这样它就可以在Cursor完成加载后换入新的。在某些时候,LoaderManager(内置于操作系统中)将调用onCreateLoader(..)GlobalCallbacks开始异步加载数据
  • Helper.bundleArgs(..)只需将查询的参数放入一个Bundle(例如列投影、排序顺序、WHERE 子句)
  • 然后我们设置Fragment's ListAdapter。此时光标仍将为空,因此它将显示加载符号或空消息,直到onLoadFinished()被调用
于 2011-09-20T16:27:51.240 回答