【问题标题】:LoaderCallbacks.onLoadFinished not called if orientation change happens during AsyncTaskLoader run如果在 AsyncTaskLoader 运行期间发生方向更改,则不会调用 LoaderCallbacks.onLoadFinished
【发布时间】:2011-08-23 19:20:14
【问题描述】:

使用 android-support-v4.jar 和 FragmentActivity(此时没有 Fragment)

我有一个 AsyncTaskLoader,我开始加载它,然后在后台线程仍在运行时更改方向。在我的日志中,我看到响应来自后台请求。响应完成,我希望 onLoadFinished() 被调用,但它永远不会。

作为一种故障排除方法,在 Manifest 中,如果我设置 android:configChanges="orientation" onLoadFinished() 会按预期调用。

我的 Activity 实现了加载器回调。在 LoaderManager.initLoader() 的源代码中,我看到如果加载器已经存在,则新的回调设置为 LoaderInfo 内部对象类,但我看不到再次调用 Loader.registerListener() 的位置。 registerListener 似乎只在调用 LoaderManagerImpl.createAndInstallLoader() 时被调用。

我怀疑由于 Activity 在方向更改时被销毁并重新创建,并且由于它是回调的侦听器,因此新的 Activity 未注册以得到通知。

谁能确认我的理解以及在方向更改后调用 onLoadFinished 的解决方案是什么?

【问题讨论】:

  • 作为另一个故障排除步骤,我添加了一个无 UI 的工作片段并将 setRetainInstance 设置为 true。 Fragment 实现了 LoaderCallbacks。 Fragment 在方向变化之间保留,但它的 onLoadFinished() 在方向变化后永远不会被调用。
  • 你在哪里打电话initLoader()?确保它位于onCreate()。顺便说一句,您可以使用LoaderManager.enableDebugLogging(true) 获取有关加载程序生命周期的一些调试信息(在 logcat 中)。

标签: android


【解决方案1】:

Nikolay 发现了问题 - 谢谢。

我从 onResume() 调用 initLoader。 Android 文档指出:

"你通常在 Activity 的 onCreate() 中初始化一个加载器 方法,或者在片段的 onActivityCreated() 方法中。”

在处理配置更改生命周期时,“通常”比我更强调一点。

我将 initLoader 调用移至 onCreate() 并解决了我的问题。

我认为原因是在 FragmentActivity.onCreate() 中,从 LastNonConfigurationInstance 中提取了一组 LoaderManagers,而在 FragmentActivity.onStart() 中,有一些关于 Loaders 和 LoaderManagers 的启动工作。在调用 onResume() 时,事情已经在进行中。当 Loader 第一次需要实例化时,从外部 onCreate() 调用 initLoader 仍然有效。

【讨论】:

  • 感谢您在这里总结,我将您的答案用于片段实现。它帮助很大!另外,感谢尼古拉提供的信息。非常乐于助人的家伙!
  • 我遇到了同样的问题。但是将 initLoader 移动到 onActivityCreated() 对我不起作用。但是将其移至 onCreate() 确实如此!不知道为什么会这样...感谢您提供了很大帮助的好答案!
  • 我也遇到了同样的问题。这个场景已经解决了。但是当加载器正在进行时,如果用户锁定手机并进入活动,则不会调用 onLoadFinished。
【解决方案2】:

实际上不是在onCreate() 中调用initLoader() 来修复它。这是对getLoaderManager() 的呼叫。总之,发生的情况是,当一个活动重新启动时,它已经知道了加载器。当您的活动点击onStart() 时,它会尝试重新启动它们,但随后它会在FragmentHostCallback.doLoaderStart()* 中点击此代码:

void doLoaderStart() {
    if (mLoadersStarted) {
        return;
    }
    mLoadersStarted = true;

    if (mLoaderManager != null) {
        mLoaderManager.doStart();
    } else if (!mCheckedForLoaderManager) {
        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
        // WTF: Why aren't we calling doStart() here?!
    }
    mCheckedForLoaderManager = true;
}

由于尚未调用 getLoaderManager(),mLoaderManager 为空。因此它会跳过第一个条件和对mLoaderManager.doStart() 的调用。

您只需在onCreate() 中调用getLoaderManager() 即可对此进行测试。你不需要在那里调用 init / restart loader。

这对我来说真的是一个错误。

* 这是代码路径,即使你没有使用片段,所以不要被它弄糊涂。

【讨论】:

    猜你喜欢
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-17
    • 1970-01-01
    • 2023-04-04
    相关资源
    最近更新 更多