38

我有一次猴子崩溃

java.lang.IllegalStateException: Failure saving state: FragmentB has target not in fragment manager: FragmentA
at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1561)
at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:475)
at com.acme.ParentActivity.onSaveInstanceState(Unknown Source)

基本上 FragmentA 加载 FragmentB 并被setTargetFragment调用以设置 FragmentB 的目标片段。

FragmentB 然后简单地调用getTargetFragment它的onCreate方法并在需要时挂在目标上。

现在,我在onSaveInstanceState目标片段的任何调用中都没有做任何事情,比如将其设置为 null、进行任何saveFragmentInstanceStateputFragment调用。问题是我应该用它做些什么吗?

提前致谢,

彼得。

** 编辑 1 ** 我正在使用旧版本的支持库,感觉这可能会在最新版本中得到修复,如果是这种情况,将进一步测试并提供进一步的更新。但是,仍然有兴趣知道我是否应该对我目前没有做的目标片段做任何事情。

** 编辑 1 ** 已在支持库的版本 8 中修复(其他未尝试)。

4

8 回答 8

36

实际上,您应该做两件事来解决此问题:

1.确保在从 FragmentA 启动 FragmentB 时使用 getChildFragmentManager() 而不是 getFragmentManager()

调用 getChildFragmentManager() 将返回宿主 Fragment 的 FragmentManager,而 getFragmentManager() 将返回宿主 Activity 的 FragmentManager。使用 getChildFragmentManager() 很重要,因为您将一个 Fragment 嵌套在另一个 Fragment 中,因此父 Fragment 应该负责处理与嵌套 Fragment 的任何事务。如果您使用 getFragmentManager(),您将遇到您现在遇到的问题。

2. 不要使用 setTargetFragment() 和 getTargetFragment(),使用 getChildFragmentManager() 时它们将不起作用

相反,使用 getParentFragment()。我相信现在Android中存在某种错误,即使您正确调用

fragmentB.setTargetFragment(fragmentA, 0);

然后显示 FragmentB,在配置更改后,从 FragmentB 调用 getTargetFragment() 将返回自身而不是 FragmentA。

于 2016-06-13T16:00:24.017 回答
14

这是一个解决方法:

把它放在导致问题的片段中:

@Override
public void onSaveInstanceState(final Bundle outState) {
    setTargetFragment(null, -1);
            ...

并记住在需要时将其设置为真正的目标片段。

于 2014-05-01T13:27:25.267 回答
6

当显示来自另一个片段的 DialogFrament 并在 DialogFragment 上使用 setTargetFragment 时,我遇到了这个问题。显示 DialogFragment 时使用 getChildFragmentManager() 解决了该问题。

  1. ActivityA 添加了 FragmentA
  2. FragmentA 使用 ActivityA 的 FragmentManager 添加了 DialogFragmentB。
  3. 调用 dialogFragmentB.setTargetFragment(fragmentA)
  4. 删除了 FragmentA 并添加了 FragmentA 的新实例
  5. 与 ActivityA 关联的 FragmentManager 仍然包含 DialogFragmentB,它以 FragmentA 的第一个实例作为目标片段。

这导致调用“失败保存状态 - 目标不在片段管理器中”异常。

于 2016-11-16T09:34:59.780 回答
5

我们最近遇到了这个问题。我们已经实现了一个扩展 android.support.v4.app 的自定义适配器。片段状态页面适配器。使用 android.support.v4.app。FragmentManager,我们在pager中设置了几个fragment,以及pager之外的其他几个fragment。片段在单个活动中进行管理。在某些情况下,我们将非分页片段的目标(使用setTargetFragment )设置为可能包含或不包含在分页适配器中的片段。因为FragmentStatePagerAdapter只维护了一定数量的 Fragment,那些被设置为目标的FragmentStatePagerAdapter被认为不再需要,被摧毁……如果具有这些目标的碎片仍然存在,则可能会出现不一致的状态。这导致每当应用程序失去焦点时(屏幕关闭或应用程序进入后台时)抛出异常,即调用onSaveInstanceState时。

为了防止这种异常,在onSaveInstanceState中,我们检查了片段管理器中当前有哪些片段。如果有任何不一致(即缺少“目标”片段),我们删除了具有该目标集的片段。在我们的例子中,我们只有三个片段来设置目标,所以我们确切地知道要寻找什么。

我不相信有任何其他方法可以处理这种情况,但如果有人有任何有用的反馈,将不胜感激。

于 2014-01-30T00:16:29.663 回答
5

我刚刚遇到了这个问题,这就是我认为正在发生的事情以及我如何解决它:

例如,当设备旋转时,您的 FragmentA 实例正在被销毁,并且正在创建另一个实例。发生这种情况时,您的 FragmentB 会继续持有对不再存在的 FragmentA 的引用。

在这种情况下,您必须将 FragmentB 的目标重置为新的 FragmentA 实例。

我在 FragmentA 中使用以下代码做到了这一点:

@Override
    public void onAttach(Context context) {

        super.onAttach(context);

        FragmentB fragment = (FragmentB) getFragmentManager().findFragmentByTag(FragmentBtag);

        if (fragment != null) {
            fragment.setTargetFragment(this, 0);
        }


    }

这样,每当 FragmentA 附加到上下文时,即:发生设备旋转,如果 FragmentB 是在第一手创建的(如果是,它将在 FragmentManager 上),则重置 FragmentB 的目标。

我希望它有所帮助。

于 2016-07-24T03:12:47.463 回答
4

确保您已将两个片段都添加到后台堆栈!

在“目标”片段之上为结果添加新的“调用”片段时,我刚刚遇到了这个问题。最初,我遇到了同样的错误,只要我在使用它们时将两个片段都添加到后台堆栈,该错误就停止了。

该问题发生在屏幕旋转上,因此很容易重现。

于 2014-07-09T21:18:09.083 回答
1

Pre-HoneyComb 和 post-Honeycomb 库之间的 onSaveInstance() 生命周期顺序几乎没有变化。请参考这篇文章了解更多信息:

http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html

于 2013-09-17T10:33:23.243 回答
0

就我而言,问题是关于调用setTargetFragment错误的片段。

曾是: FragmentA.setTargetFragment(FragmentB);

应该: FragmentB.setTargetFragment(FragmentA);

于 2018-03-06T08:44:50.447 回答