【问题标题】:Support Library 27.1.0 onLoaderFinished returns a closed cursor when starting a Fragment支持库 27.1.0 onLoaderFinished 在启动 Fragment 时返回关闭的游标
【发布时间】:2025-12-03 06:20:13
【问题描述】:

更新到支持库 27.1.0 后,我的应用程序崩溃了,这似乎是由于 CursorLoader 在 onLoaderFinished() 中返回关闭的游标所致。

我在 Fragment 中使用 Loader,我没有手动关闭光标。如果我回滚到支持库 27.0.2,一切正常。这是堆栈跟踪:

03-27 16:27:58.653 18706 18706 E AndroidRuntime: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteQuery: ...
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:58)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:151)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:123)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:237)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:259)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.database.CursorWrapper.moveToFirst(CursorWrapper.java:71)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at com.example.test.onLoadFinished(LeaderBoardFragment.java:104)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at com.example.test.onLoadFinished(LeaderBoardFragment.java:41)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.LoaderManagerImpl$LoaderObserver.onChanged(LoaderManagerImpl.java:221)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LiveData.considerNotify(LiveData.java:109)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LiveData.dispatchingValue(LiveData.java:121)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LiveData.access$400(LiveData.java:59)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:416)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:368)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:292)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:332)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:137)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.arch.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:123)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.Fragment.performStart(Fragment.java:2377)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1752)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1821)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:797)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2595)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2382)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2337)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2244)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:702)
03-27 16:27:58.653 18706 18706 E AndroidRuntime:    at android.os.Handler.handleCallback(Handler.java:790)

我在 onLoaderFinished() 中的代码如下:

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    super.onLoadFinished(loader, cursor);
    int score;
    if (loader.getId() == MY_LOADER_ID && cursor != null
            && getAbstractAdapter() != null) {
        getAbstractAdapter().swapCursor(cursor);

        if (cursor.getCount() > 0 && cursor.moveToFirst()) {
            score = cursor.getInt(cursor
                    .getColumnIndex(0));
        }
    }
}

调用cursor.moveToFirst()时崩溃

来自onLoaderReset()的代码

@Override
public void onLoaderReset(Loader<Cursor> arg0) {
    mAdapter.swapCursor(null);
}

【问题讨论】:

  • 你能在你使用光标的地方添加代码吗?听起来您使用的是changeCursor,而不是swapCursor
  • @ianhanniballake 感谢您的浏览。请查看已编辑的问题,其中包含光标使用的代码。
  • @ianhanniballake 在对代码库进行更多挖掘之后,我发现加载程序只是开始使用restartLoader() 而不是首先调用initLoader()。深入研究 SupportLibrary 代码,看起来调用 restartLoader 将关闭“CursorLoader#onReset”中的游标。奇怪的是,LiveData 似乎保留了先前交付的光标(现已关闭)并在交付新光标之前将其返回给onLoaderFinished
  • 听起来像this issue,将在 27.1.1 中修复,即将发布。
  • @ianhanniballake 感谢您的信息。我会等待那个版本,看看它是否能解决我的问题。非常感谢您帮助社区。​​span>

标签: android android-support-library loader


【解决方案1】:

我在支持库 28.0 中遇到了类似的问题。虽然我在片段的下一次出现时关闭了片段 onStop() 中的光标,但我得到了关闭光标 - 这对我有帮助

override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor?) {
        if (loader.id == LOADER_ID ) {
            if (cursor?.isClosed == true)
                loaderManager.restartLoader(LOADER_ID, null, this)
            else
                adapter.swapCursor(cursor)
        }
    }

虽然它看起来像解决方法 - 我认为加载器以某种方式负责管理游标的生命周期并在旧 id 关闭时确保新的。

【讨论】:

    最近更新 更多