Android 的游标竞争条件?

Race conditions in Cursors for Android?

所以我有这个应用程序可以通过提供程序将数据加载到游标中。 然后游标用于获取应用程序要使用的数据。 加载过程由 LoaderManager API.

完成

现在问题出现在我在某些情况下从onLoadFinished()调用swapCursor()之后;游标报告有正确数量的数据,但是当我尝试访问它时,我得到一个 CursorIndexOutOfBoundsException.

奇怪的是,我确切地知道这发生在哪一行,所以我在那里放置了一个断点以暂停所有线程并尝试检查数据以查看发生了什么,突然错误消失了。

现在通过反复试验,我认为即使我什么都不做,问题也会消失。在它暂停一切之后几乎什么都没有。如果我在恢复执行前等待几秒钟,数据就完全可以访问了。

所以我的问题是:有人知道 Android 操作系统是否在后台执行某些创建竞争条件的操作吗?我真的不明白这怎么会是我这边的一个错误,因为当我测试它时我暂停了所有线程,所以我的应用程序在我等待问题解决时不能做任何事情。

作为旁注,如果我只是用 changeCursor() 替换 swapCursor() 调用(这样做意味着我必须使用 restartLoader() 而不是 initLoader() 由于其他一些系统的功能)错误消失了,但我在某处读到这不是正确的方法,因为它不能正确处理游标的关闭(我认为这是我必须使用的原因restartLoader(),但我现在真的想不起来了)。

部分代码摘录:

@Override
public void onCreate( Bundle savedInstanceState ) {
    super.onCreate( savedInstanceState );
    ...
    getLoaderManager().initLoader( ACTIVE_TEAM_LOADER, null, this );
}

...

@Override
public void onLoadFinished( Loader<Cursor> loader, Cursor data ) {
    switch ( loader.getId() ) {
    case ACTIVE_TEAM_LOADER:
        activeTeamAdapter.swapCursor(
            new MergeCursor( new Cursor[]{ data, createNewCursor } ) );
...
}

还有违规行,在堆栈深处调用 CursorAdapter.bindView():

long value = data.getLong( data.getColumnIndex( getDBName() ) );

对我来说,光标中的数据似乎尚未正确加载。

问题是由于swapCursor()没有关闭之前的MergeCursor游标造成的。关闭前一个游标解决了问题,但引入了一个新问题,因为您不应该从 onLoadFinished() 关闭游标,并且在关闭 MergeCursorMergeCursor 也会关闭所有子游标.

每当我使用适配器仅显示 MergeCursors(一些适配器显示 MergeCursors 和 MatrixCursors 时,通过切换回使用 changeCursor() 解决了这个问题当没有来自 onLoadFinished() 的数据并且由于某种原因 MatrixCursors 似乎需要在两次使用之间关闭它们所以这不适用于它们,我不知道为什么)并将所有游标包装在class 无视关闭。

onLoadFinished() 摘录:

Cursor[] cursors = new Cursor[] { new UnclosableCursor( data ), createNewCursor };
activeTeamAdapter.changeCursor( new MergeCursor( cursors ) );

包装器:

public class UnclosableCursor extends CursorWrapper {

    public UnclosableCursor( Cursor cursor ) {
        super( cursor );
    }

    @Override
    public void close() {}

}

此答案的先前版本暗示这与转换有关,但经过更多研究后,这似乎只是问题的症状,而不是实际问题。