失败保存状态 - 目标不在片段管理器中(setTargetFragment)

时间:2012-05-03 17:06:45

标签: android android-fragments

我的猴子撞车了

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(尚未尝试其他版本)。

8 个答案:

答案 0 :(得分:29)

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

<强> 1。从FragmentA启动FragmentB时,请确保使用getChildFragmentManager()NOT getFragmentManager()

调用getChildFragmentManager()将返回托管片段的FragmentManager,而getFragmentManager()将返回托管Activity的FragmentManager。使用getChildFragmentManager()非常重要,因为您将Fragment嵌套在另一个Fragment中,因此父Fragment应负责处理嵌套Fragment的任何事务。如果你使用getFragmentManager(),你将遇到你现在遇到的问题。

<强> 2。不要使用setTargetFragment()和getTargetFragment(),它们在使用getChildFragmentManager()时不起作用

相反,请使用getParentFragment()。我相信Android中存在某种错误,即使你正确地调用了

fragmentB.setTargetFragment(fragmentA, 0);

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

答案 1 :(得分:13)

这是一种解决方法:

将其放入导致问题的片段中:

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

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

答案 2 :(得分:5)

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

为防止此异常,我们在 onSaveInstanceState 中检查了片段管理器中当前的片段。如果存在任何不一致(即,“目标”片段丢失),我们删除了具有该目标集的片段。在我们的例子中,我们只有三个片段来设置目标,因此我们确切地知道要查找的内容。

我不相信有任何其他方法可以处理此案例,但如果有人有任何有用的反馈意见,我们将不胜感激。

答案 3 :(得分: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附加到Context,即:设备轮换发生,FragmentB的目标就会被重置,如果FragmentB是在第一手创建的(如果是的话,它将在FragmentManager上)。 / p>

我希望它有所帮助。

答案 4 :(得分:5)

从另一个Fragment显示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的第一个实例作为目标片段。
  6. 这导致调用“失败保存状态 - 目标不在片段管理器中”异常。

答案 5 :(得分:4)

请确保您已将这两个片段添加到Backstack中!

我在“目标”片段顶部添加新的“被调用”片段时遇到了这个问题。最初,我得到了同样的错误,只要我在使用它们时将两个片段都添加到后台堆栈就会停止发生。

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

答案 6 :(得分:1)

关于Pre-HoneyComb和后蜂窝库之间onSaveInstance()生命周期顺序的变化很少。有关详细信息,请参阅此文章:

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

答案 7 :(得分:0)

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

当时: FragmentA.setTargetFragment(FragmentB);

应该是: FragmentB.setTargetFragment(FragmentA);