2

我收到一些用户的 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 

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

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

有任何想法吗?

4

2 回答 2

1

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

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

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

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

来自AOSP文档;

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

内容提供者基础知识

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

于 2013-02-26T00:14:20.667 回答
0

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

public synchronized void onDestroy() {
    if (this.cursor != null){
        this.cursor.close();
        this.cursor = null
    }
}
于 2016-12-14T07:52:59.223 回答