【问题标题】:Merging cursors during onLoadFinished() causes StaleDataException after rotation在 onLoadFinished() 期间合并游标会导致旋转后出现 StaleDataException
【发布时间】:2013-05-06 05:51:33
【问题描述】:

我正在使用 loaderManager 从数据库中加载一些结果。不幸的是,以下代码在旋转设备后会产生 StaleDataException

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
{
    // If we've returned results, then pass them and the webSearches cursor along to be displayed
    if(cursor.moveToFirst())
    {
        // Get a cursor containing additional web searches and merge it at the end of the results cursor 
        MatrixCursor searchesCursor = getWebSearchesCursor(searchTerm, false);
        Cursor[] cursors = { cursor, searchesCursor };
        // TODO: Figure out why merging cursors here causes staledataexception after rotation
        Cursor results = new MergeCursor(cursors);
        // Display the cursor in the ListView
        adapter.changeCursor(results);
    }
    // If no results were returned, then return suggestions for web searches
    else
    {
        // Get a cursor containing additional web searches 
        MatrixCursor noResults = getWebSearchesCursor(searchTerm, true);
        adapter.changeCursor(noResults);    
    }

    // Show the listView and hide the progress spinner
    toggleListView(SHOW);
}

getWebSearchesCursor() 的调用会返回一个MatrixCursor,并带有一些附加的搜索提示,以伴随任何返回的结果。我发现将 adapter.changeCursor(results) 更改为 adapter.changeCursor(cursor) 可以修复错误,因此看起来将 MatrixCursor 合并到返回的光标会产生错误。

我的问题是,为什么?

如果返回任何结果,我希望能够向返回的光标添加其他项目,以便用户可以选择在几个网站上执行搜索。有没有更好的方法来合并游标,这样我在旋转后就不会出现这个异常?

【问题讨论】:

    标签: android staledataexception matrixcursor mergecursor


    【解决方案1】:

    如果您已经开始在各处使用swapCursor() 而不是changeCursor(),那么我希望您也开始在这些地方处理光标关闭问题。

    changeCursor() 将关闭旧光标,这是故意的,当您直接使用onLoadFinished() 提供的光标时,它可以完美地工作。这样做是为了让您不必担心关闭它。

    当你旋转你的设备时,android系统会检查它上次发送给你的光标是否还没有关闭,并再次发送它,而不是花费资源来创建一个新的。您的代码将此光标包装在MergeCursor新实例 中,该实例被传递给changeCursor(),它发现这与之前获得的对象不同,并决定关闭旧实例。由于MergeCursor 仅包装您传递给它的游标,而不是复制其中的数据,因此您的新实例现在包含(至少)一个封闭游标。

    要正确处理此问题,您需要编写一些自己的代码来检查您通过onLoadFinished() 获得的光标是否与您当前MergeCursor 实例中的光标相同,并且只关闭现有实例如果你得到一个新的光标。当然,您还需要跟踪包装在同一 MergeCursor 实例中的其他游标。

    【讨论】:

      【解决方案2】:

      几天前又出现了这个问题,我很幸运地偶然发现了一个解决方案。

      我发现我应该使用 swapCursor() 而不是 changeCursor()。 According to the Android docs:

      更换新光标,返回旧光标。与 changeCursor(Cursor) 不同,返回的旧 Cursor 没有关闭。

      ...

      如果给定的新Cursor与之前设置的Cursor是同一个实例,也返回null。

      最后一部分似乎是关键。上面问题中提到的错误可以追溯到 CursorAdapter 在合并光标上阻塞,因为它在旋转后尝试重绘片段时被关闭。通过改用 swapCursor(),CursorAdapter 能够重用“旧”合并游标,而不是质疑其有效性并抛出 StaleDataException。

      我在这里做一些假设;也许更了解 Android 内部运作的人可以证实或否认我的推理。

      【讨论】:

        猜你喜欢
        • 2015-12-11
        • 1970-01-01
        • 1970-01-01
        • 2016-08-04
        • 1970-01-01
        • 1970-01-01
        • 2021-04-03
        • 2020-07-23
        相关资源
        最近更新 更多