我的猴子撞车了
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,进行任何saveFragmentInstanceState
,putFragment
等调用。问题是我应该用它做些什么吗?
提前致谢,
彼得。
**编辑1 ** 我正在使用旧版本的支持库,并且感觉这可以在最新版本中修复,如果是这种情况,将进一步测试并提供进一步的更新。但是,仍然有兴趣知道我是否应该对我目前没有做的目标片段做任何事情。
**编辑1 **已修复支持库的版本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()解决了该问题。
这导致调用“失败保存状态 - 目标不在片段管理器中”异常。
答案 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);