获取SQLiteCursorLoader观察数据变化
我正在尝试使用使用 Commonsware 的 Loader 的适配器来实现 DataListFragment 。该Loader直接使用SQLiteDatabase,不需要使用ContentProviders。
android 参考文献中有关 Loaders 的说明: “当加载程序处于活动状态时,它们应该监视数据源,并在内容发生变化时提供新的结果。”
在我的 SQLiteCursor 实现(如下)下,这种情况不会发生。 OnLoadFinished()
被调用一次,仅此而已。据推测,可以在底层数据库发生更改的地方插入 Loader.onContentChanged() 调用,但一般来说数据库代码类不知道加载器,所以我不确定最好的方法关于实施这一点。
有没有人对使 Loader “数据感知”有任何建议,或者我应该将数据库内容包装为 ContentProvider 并使用 CursorLoader 代替?
import com.commonsware.cwac.loaderex.SQLiteCursorLoader;
public class DataListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
protected DataListAdapter mAdapter; // This is the Adapter being used to display the list's data.
public SQLiteDatabase mSqlDb;
private static final int LOADER_ID = 1;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
int rowlayoutID = getArguments().getInt("rowLayoutID");
// Create an empty adapter we will use to display the loaded data.
// We pass 0 to flags, since the Loader will watch for data changes
mAdapter = new DataListAdapter(getActivity(),rowlayoutID, null , 0);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
LoaderManager lm = getLoaderManager();
// OnLoadFinished gets called after this, but never again.
lm.initLoader(LOADER_ID, null, this);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String sql="SELECT * FROM "+TABLE_NAME+";";
String[] params = null;
SQLiteCursorLoader CursorLoader = new SQLiteCursorLoader(getActivity(), mSqlDb, sql, params);
return CursorLoader;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the old cursor once we return.)
mAdapter.swapCursor(data);
// The list should now be shown.
if (isResumed()) { setListShown(true);}
else { setListShownNoAnimation(true); }
}
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
I'm trying to implement a DataListFragment with an adapter that uses a Loader from Commonsware. This Loader uses a SQLiteDatabase directly and doesn't require the use of ContentProviders.
The android reference states about Loaders:
"While Loaders are active they should monitor the source of their data and deliver new results when the contents change."
Under my SQLiteCursor implementation (below), this does not happen. OnLoadFinished()
gets called once and that's it. Presumably, one could insert Loader.onContentChanged()
calls where the underlying database gets changed, but in general the database code class does not know about loaders, so I'm not sure about the best way to go about implementing this.
Does anyone have any advice on making the Loader "data aware", or should I wrap the database stuff in as a ContentProvider and use CursorLoader instead?
import com.commonsware.cwac.loaderex.SQLiteCursorLoader;
public class DataListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
protected DataListAdapter mAdapter; // This is the Adapter being used to display the list's data.
public SQLiteDatabase mSqlDb;
private static final int LOADER_ID = 1;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
int rowlayoutID = getArguments().getInt("rowLayoutID");
// Create an empty adapter we will use to display the loaded data.
// We pass 0 to flags, since the Loader will watch for data changes
mAdapter = new DataListAdapter(getActivity(),rowlayoutID, null , 0);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
LoaderManager lm = getLoaderManager();
// OnLoadFinished gets called after this, but never again.
lm.initLoader(LOADER_ID, null, this);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String sql="SELECT * FROM "+TABLE_NAME+";";
String[] params = null;
SQLiteCursorLoader CursorLoader = new SQLiteCursorLoader(getActivity(), mSqlDb, sql, params);
return CursorLoader;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the old cursor once we return.)
mAdapter.swapCursor(data);
// The list should now be shown.
if (isResumed()) { setListShown(true);}
else { setListShownNoAnimation(true); }
}
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Loader
文档存在缺陷。Android 本身内置的 100%
Loader
实现“监视数据源并在内容更改时提供新结果”。由于目前 Android 本身只内置了一个Loader
实现,因此他们的文档就目前而言是准确的。然而,引用我的一两个小时后应该发布的书籍更新:
如果您通过 SQLiteCursorLoader 路由所有数据库修改,我确实计划增强 SQLiteCursorLoader ,以便至少更加了解数据库更改。这也有限制,因为您不会在活动之间共享
Loader
对象(更不用说从服务访问它们了)。CursorLoader 如此工作的唯一原因是它使用了 ContentProvider —— 一个可以了解所有操作的单例。
目前,代码的任何部分负责插入、更新和删除,都需要点击肩上的 SQLiteCursorLoader 并使其更新,或者通知活动更改(例如,从
Service
广播),以便 Activity 可以点击肩膀上的SQLiteCursorLoader
。The
Loader
documentation is flawed.100% of
Loader
implementations built into Android itself "monitor the source of their data and deliver new results when the contents change". Since there is only oneLoader
implementation built into Android itself as of now, their documentation is accurate as far as that goes.However, quoting a book update of mine that should be released in an hour or two:
I do plan on augmenting
SQLiteCursorLoader
to be at least a bit more aware of database changes, if you route all database modifications through it. That too will have limitations, because you don't shareLoader
objects between activities (let alone have access to them from services).The only reason
CursorLoader
works as it does is because it uses aContentProvider
-- a singleton that can therefore be aware of all operations.At the moment, whatever portion of your code is responsible for inserts, updates, and deletes will either need to tap the
SQLiteCursorLoader
on the shoulder and have it update, or notify the activity of the change (e.g., broadcast from aService
) so the activity can tap theSQLiteCursorLoader
on the shoulder.