我在我的应用程序中广泛使用Cursors
来加载和偶尔从数据库写入信息和向数据库写入信息。我已经看到Honeycomb和兼容包有新的Loader
类,旨在帮助以“良好”的方式加载数据。
基本上,这些新类(特别是CursorLoader
)是否比以前的数据管理方法好得多?例如,CursorLoader
优于托管Cursors
有什么好处?
我使用ContentProvider
来处理数据,这显然需要Uris
,但这与initLoader()
方法有何关系?我必须设置每个Fragments
以单独使用装载程序吗?并且每个加载器的id需要多么独特,它是在我的应用程序范围内还是仅仅是一个片段?有没有简单的方法可以简单地将Uri
传递给CursorLoader来查询我的数据?
目前我所能看到的是,Loaders添加了一个不必要的额外步骤来将我的数据导入我的应用程序,那么有人可以更好地向我解释这些吗?
答案 0 :(得分:44)
在您的应用中使用CursorLoader
优于Activity.managedQuery()
有两个主要好处:
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
希望有帮助!
答案 1 :(得分:10)
如果有人发现自己处于类似的情况,那就是我所做的:
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
,因为GlobalCallbacks
会在Cursor
onLoadFinished(..)
LoaderManager
我们要初始化新的CursorLoader
。我们提供了一个新的GlobalCallbacks
实例(实现Loader.Callbacks
),然后监视光标的加载。我们也必须为它提供适配器,因此它可以在完成加载后交换新的Cursor
。在某些时候,LoaderManager
(内置于操作系统中)将调用onCreateLoader(..)
的{{1}}并开始异步加载数据GlobalCallbacks
只需将查询的参数放入Helper.bundleArgs(..)
(例如列投影,排序顺序,WHERE子句)Bundle
的{{1}}。此时光标仍为空,因此在调用Fragment
之前它将显示加载符号或空消息