获取SQLiteCursorLoader观察数据变化

发布于 2024-12-29 18:01:05 字数 2353 浏览 1 评论 0原文

我正在尝试使用使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

会傲 2025-01-05 18:01:05

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 one Loader 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:

There is nothing in the framework that requires this
behavior. Moreover, there are some cases where is clearly a bad idea to do
this – imagine a Loader loading data off of the Internet, needing to
constantly poll some server to look for changes.

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 share Loader objects between activities (let alone have access to them from services).

The only reason CursorLoader works as it does is because it uses a ContentProvider -- 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 a Service) so the activity can tap the SQLiteCursorLoader on the shoulder.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文