【问题标题】:How does a cursor used by a RemoteViewService get deactivatedRemoteViewService 使用的游标如何被停用
【发布时间】:2016-12-14 15:52:59
【问题描述】:

我收到一些用户的 ACRA 异常报告,指出向我的 appwidget (RemoteViewService) 提供数据的游标已停用/关闭。它从来没有亲身发生在我身上,但在有点问题的地方发生的就足够了。

这是我的 RemoteViewService 的代码:

    public static class ListItemService extends RemoteViewsService {

        public RemoteViewsFactory onGetViewFactory(final Intent intent) {

            return new RemoteViewsFactory() {

                private MyCursor cursor;

                public void onCreate() {
                    // Nothing
                }

                public synchronized void onDestroy() {
                    if (this.cursor != null)
                        this.cursor.close();
                }

                public synchronized RemoteViews getViewAt(int position) {
                      // Here I read from the cursor and it crashes with
                      // the stack trace below
                }

                public int getCount() {
                      return ((this.cursor != null) ? this.cursor.getCount() : 0);
                }

                public int getViewTypeCount() {
                    return 1;
                }

                public boolean hasStableIds() {
                    return true;
                }

                public long getItemId(int position) {
                    return position;
                }

                public RemoteViews getLoadingView() {
                    return null;
                }

                public synchronized void onDataSetChanged()
                {
                    if (this.cursor != null)
                        this.cursor.close();

                    this.cursor = getApplicationCntext().getContentResolver().query(myUri, null, null, null, null);
                }
            };

堆栈跟踪因平台版本而异。例如,我在 4.0.3 上得到以下内容:

android.database.StaleDataException: Attempting to access a closed CursorWindow.Most probable cause: cursor is deactivated prior to calling this method.

在 2.3 上,我得到一个:

java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery 

除了onDestroy()onDataSetChanged() 之外,我一生都无法弄清楚是谁或什么东西关闭了我的光标。一些用户报告说,当崩溃发生时,他们并没有积极地使用应用程序。

我怀疑对 ContentProvider 的多次调用可能会返回相同的光标,当我显示使用相同查询的 UI 时,它们会互相踩踏。但情况似乎并非如此,因为光标对象不同。

有什么想法吗?

【问题讨论】:

    标签: android android-sqlite android-cursor android-appwidget


    【解决方案1】:

    在我看来像多个线程之间的同步问题,一个关闭前一个光标,一个立即访问它。

    您可能需要考虑在第一时间关闭光标,例如 onPause 事件。

    另外 - 您可以添加安全预防措施,例如在再次访问之前检查 cursor.isClosed()。您还可以在代码中添加一些同步。

    使用本地变量获取新游标并且仅在完成后替换前一个游标并关闭它的辅助方法可能是同时更快的解决方案。

    来自AOSPdoc;

    此接口提供对结果集的随机读写访问 由数据库查询返回。不需要光标实现 要同步,因此使用来自多个线程的游标的代码应该 使用光标时执行自己的同步。

    来自Content provider basics

    ContentResolver.query() 客户端方法始终返回一个 Cursor,其中包含由查询投影指定的与查询的选择条件匹配的行的列。 Cursor 对象提供对其包含的行和列的随机读取访问。使用 Cursor 方法,您可以遍历结果中的行,确定每列的数据类型,从列中获取数据,并检查结果的其他属性。某些 Cursor 实现会在提供者的数据更改时自动更新对象,或者在 Cursor 更改时触发观察者对象中的方法,或两者​​兼而有之。

    【讨论】:

    • 我给了你赏金——但我不确定这是否真的是问题,所以我没有“接受”答案。除非 query() 返回的游标以某种方式得到同一个底层数据库对象的支持,否则我不知道他们如何能踩到对方的脚趾。返回的 Java 对象是不同的——我通过打印它们的 hashCode() 来验证这一点。如果我使用 ContentProvider,这绝对是一个问题。如果我直接使用 SqlLite 对象查询数据库,我不会得到这种行为。如果有帮助,我很乐意发布我的 ContentProvider 代码。
    • 好吧,您使用游标的实现有点简单,而且看起来无论如何也应该在不同的线程上进行查询,即使我们确实想坚持使用它。在您必须让活动为您管理它们的日子里以及在引入 CursorLoader 之前,游标有点坏了。查看github.com/commonsguy/cwac-loaderex 并告诉我它是否有帮助,因为它应该为您提供所需的所有功能以及更多功能。如果这太多了,还有更简单的反向移植想法来实现一个简单的游标加载器,这基本上让它b
    • 我为可滚动的 AppWidget 而不是 Activity 列出的代码。我基本上从文档中获取了示例。再一次,如果我将 ContentProvider 提供的游标替换为直接从数据库创建的游标,我不会遇到问题。
    • 我明白这一点,但只是提到了一些游标历史,以供一般知识。基本上是同一个问题。如果您以其他方式解决了它,您可以发布自己的解决方案并接受它,以便其他人也能理解您的想法。
    • 我没有解决。我想使用 ContentProvider 查询,但我不得不使用直接数据库查询。
    【解决方案2】:

    尝试在onDestory()方法上添加this.cursor = null

    public synchronized void onDestroy() {
        if (this.cursor != null){
            this.cursor.close();
            this.cursor = null
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-01-17
      • 2015-10-23
      • 1970-01-01
      • 2022-07-29
      • 1970-01-01
      • 1970-01-01
      • 2020-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多