RemoteViewService使用的游标如何停用

时间:2013-02-19 08:04:00

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

我从某些用户那里得到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时,它们会相互踩踏。但由于光标对象不同,情况似乎并非如此。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

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

您可能需要考虑首次关闭光标,例如onPause事件。

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

一个辅助方法,用一个本地var获取新游标,只有一次完成,替换前一个并在此期间关闭它可能是一个更快的解决方案。

来自AOSP doc;

  

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

来自Content provider basics

  

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

答案 1 :(得分:0)

尝试在this.cursor = null方法

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