数据库更改时,Android SimpleCursorAdapter 不会更新

Posted

技术标签:

【中文标题】数据库更改时,Android SimpleCursorAdapter 不会更新【英文标题】:Android SimpleCursorAdapter doesn't update when database changes 【发布时间】:2010-12-31 10:52:58 【问题描述】:

我有一个 android ListActivity,它由数据库 Cursor 通过 SimpleCursorAdapter 支持。

单击项目时,数据库中对应行中的标志字段被切换,列表中的视图需要更新。

问题是,当更新的视图离开屏幕并被回收时,当它返回视图时,旧值会显示在视图上。每当重绘 thr 列表(方向更改等)时,都会发生同样的事情。

我用notifydatasetchanged()刷新游标适配器,但是好像没有效果。

我应该如何更新数据库以更新光标?

【问题讨论】:

【参考方案1】:

这很容易。

private Db mDbAdapter;
private Cursor mCursor;
private SimpleCursorAdapter mCursorAd;

.....................................
//After removing the item from the DB, use this
.....................................

 mCursor = mDbAdapter.getAllItems();
 mCursorAd.swapCursor(mCursor);

或者使用 CursorLoader...

【讨论】:

【参考方案2】:

requery() 已被弃用,只需在 CursorAdapter 的子类中实现类似这样的简单 updateUI() 方法并在数据更新后调用它:

private void updateUI()
    swapCursor(dbHelper.getCursor());
    notifyDataSetChanged();

【讨论】:

【参考方案3】:

当您更改数据库中要反映在Cursor 中的数据时,请在Cursor 上调用requery()(或Cursor 填充的内容,例如ListView 通过CursorAdapter)。

Cursor 类似于 ODBC 客户端游标——它包含查询结果表示的所有数据。因此,仅仅因为您更改了数据库中的数据,Cursor 不会知道这些更改,除非您通过 requery() 刷新它。


更新:这整个问题和答案集都应该因年老而被删除,但这显然是不可能的。任何寻求 Android 答案的人都应该记住,Android 是一个瞬息万变的目标,2009 年的答案通常比新的答案更糟糕。

当前的解决方案是获取一个新的Cursor 并在CursorAdapter 上使用changeCursor()swapCursor() 来影响数据更改。

【讨论】:

那么 notifydatachanged 是做什么的呢? 没有“notifydatachanged”。如果您的意思是适配器上的 notifyDataSetChanged(),这就是 SimpleCursorAdapter 告诉 ListView 数据已更改的方式。从文档中引用,“通知附加的视图基础数据已更改,它应该自行刷新。”但是,您的问题不在于 Adapter 告诉 ListView 有关更改 - 您的问题是 Adapter 不知道数据已更改。调用 requery() 是使用 CursorAdapter 解决该问题的方法。 现在说得通了。我误解了数据流。 requery() 已弃用。相反,您应该发出一个新的Cursor 并通过adapter.changeCursor(myCursor) 将其发送到您的CursorAdapter。 See the docs 在弃用通知中。【参考方案4】:

不清楚是否将CursorAdapter的autoRequery属性设置为true

适配器将检查autoRequery 属性;如果是false,则光标不会改变。

【讨论】:

protected void init (Context context, Cursor c, boolean autoRequery) 此方法已弃用。不要使用这个,使用普通的构造函数。这将在未来被删除。【参考方案5】:

如果使用加载器和自动生成的光标,您可以调用:

getLoaderManager().restartLoader(0, null, this);

在您的活动中,在更改数据库上的某些内容之后,重新生成新游标。 不要忘记定义事件处理程序:

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) 
    CursorLoader cursorLoader =
            new CursorLoader(this,
                    YOUR_URI,
                    YOUR_PROJECTION, null, null, null);
    return cursorLoader;


@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) 
    adapter.swapCursor(data);


@Override
public void onLoaderReset(Loader<Cursor> loader) 
    adapter.swapCursor(null);

【讨论】:

从 Stack Overflow 周围尝试了六种不同的东西,这就是最终对我有用的东西。谢谢! 这正是我正在寻找的答案,使用一个简单的适配器,并调用 swapCursor onLoadFinished。 工作了,但我必须添加这个:当列表视图片段注册用户单击时,会导致更新行的值,然后将其插入数据库,新游标自动创建onCreateLoader() 中的 cursorloader 必须传递给(在我的情况下)扩展 simpleCursorAdapter 的自定义适配器,因为我发现没有其他方法可以通知方法 getView()(执行视图更新)有关新光标的信息。 GetView() 使用旧光标,直到重新启动整个片段。因此,我在 customadapter 中创建了一个 setCursor(),并从 onCreateLoader() 调用它。然后它起作用了。【参考方案6】:

requery 现已弃用。来自documentation:

此方法已弃用。 不要使用这个。只需请求一个新光标,这样您就可以异步执行此操作,并在新光标返回后更新您的列表视图。

获得一个新的游标后,可以使用adapter.changeCursor(cursor)。这应该会更新视图。

【讨论】:

感谢您的信息,我一直在 Honeycomb 上遇到与 cursor.requery() 相关的崩溃,也许这是它背后的原因。 常见的情况是从 onClickListener() 改变值 令我困惑的是,一方面,我们通过构造函数发送初始光标(即查询是在 Adpater 之外编写的)但另一方面, onlickLister 被定义为适配器内的嵌套类。所以对新游标的查询将写在适配器类中。这可能会导致重复代码。在源代码中只编写一次查询的正确设计是什么?

以上是关于数据库更改时,Android SimpleCursorAdapter 不会更新的主要内容,如果未能解决你的问题,请参考以下文章

当实时数据将由 FCM 更改时,我如何在 android 中获得通知?

如何在运行时更改动态添加的 Android 视图中的数据

更改实时数据时,Android Composelazycolumn 不更新

android - 在更改 EditText 值时无法更新列表视图

Android:在方向更改时,总是调用 Web 服务 [重复]

当Android中Firebase数据库中的数据发生更改时将数据发送到应用程序[关闭]