Android FragmentManagerImpl.dispatchResume()不按顺序恢复片段

时间:2015-02-02 04:04:53

标签: android android-fragments

我在Android中遇到了一个非常奇怪的问题,我无法弄清楚它为什么会发生或如何围绕它进行编码。我真的相信这是一个Android错误。

我有一个MainActivity,它包含一个名为main_container的FrameLayout(它的高度和宽度都是match_parent,因为每个片段应该是“向用户显示”的唯一片段)。从MainActivity,我像这样添加片段A:

mFragmentManager.beginTransaction()
        .replace(R.id.main_container, frag, fragTag)
        .commit();

从那里开始,片段A,在用户点击视图时,会像这样添加片段B(“frag”和“fragTag”与上面的代码片段不同):

mFragmentManager.beginTransaction()
        .setCustomAnimations(R.anim.slide_in_right, 0, 0, R.anim.slide_out_right)
        .add(R.id.main_container, frag, fragTag)
        .addToBackStack(null)
        .commit();

从这里开始,片段B将像这样添加片段C(再次,“frag”和“fragTag”与前两个片段的值不同):

mFragmentManager.beginTransaction()
        .setCustomAnimations(R.anim.slide_in_right, 0, 0, R.anim.slide_out_right)
        .add(R.id.main_container, frag, fragTag)
        .addToBackStack(null)
        .commit();

所以在这一点上,在后台,我们应该有片段A - >片段B - >片段C。

片段C在用户单击视图时调用MediaPicker。这样做会调用所有片段的onPause方法,并将应用程序放在后台。现在,当用户选择一个图像时,应用程序将恢复,但是这里发生了错误...它按此顺序恢复,正如每个片段的onResume方法中的断点所证明的那样:

片段A - >片段C - >片段B

这会导致各种各样的问题,因为我的每个片段都将自己注册为MainActivity中的侦听器,以处理后退按钮点击。这种逻辑依赖于顺序正确。出于某种原因,它仍然显示片段C在顶部,但onResume肯定被称为无序。

可能更糟糕的是...而不是点击MediaPicker,您只需旋转手机即可进行配置更改。这表现出与A - >重新排序相同的行为。 C - > B但是在这种情况下它实际上显示错误的片段在顶部。它在顶部显示片段B.

这是一个设计点,你不能依赖Android以你添加到backstack的相同顺序恢复片段,我应该围绕它编码?或者我做错了什么?或者这真的是一个Android错误?到目前为止,我还不是Android开发的新手,但这个让我感到难过。

修改

我已经确定了发生了什么,显然它是设计的。这对我来说似乎很疯狂,我不同意它背后的逻辑。我或许可以用反射解决这个问题,但我不喜欢这样做。无论如何,关于这个问题。

问题在于FragmentManagerImpl跟踪活动片段的方式。它有一个ArrayList来跟踪活动片段以及当所有内容都暂停时(例如在我的情况下,我开始有意从媒体库中获取照片,因此它正在离开我的应用),在恢复时进入我的应用程序,它将片段移回到它们在该ArrayList中的same order中。听起来不错,嗯?

这是我的问题。当事物从那个ArrayList中取出时,它们不会删除()项,它们只是将它设置为null然后有逻辑重用那个空的“槽”(github链接中的第1168行)当下一个片段出现时。在我的例子中,在ArrayList中留下一个洞的瞬态片段是DialogFragment。将其重新放回原始报告中,片段A显示一个DialogFragment ...单击DialogFragment中的某个按钮会调出片段B.单击片段B中的另一个视图会显示片段C.但是这里发生的事情是ArrayList FragmentManagerImpl保持不变单击DialogFragment中的按钮后跟踪:

{FragA,null(曾经是DialogFragment),FragB}

显然,在FragB移动到活动状态后,DialogFragment已经移出活动状态,从而留下了一个漏洞。所以现在我们单击FragB中的视图来调出FragC,ArrayList看起来像这样:

{FragA,FragC(重用DialogFragment的插槽),FragB}

我们去找媒体选择器,回来,然后就我如何首先实例化这些片段而言,这些片段已经无序恢复了。这对我来说没有任何意义,如果你没有使用断点进入操作系统代码,你就永远不知道为什么Android的行为方式不像你告诉它的那样。看起来像删除你删除的片段的ArrayList.remove()会更容易,因此不会留下任何漏洞。

就像我说的那样,我可以通过反射解决这个问题...但我对此持怀疑态度,因为所有片段中都有这个mIndex变量,它对应于该ArrayList(mActive)中它的插槽的索引。所以我必须确保保持同步......现在我依赖于知道操作系统代码是如何工作的。 :(

1 个答案:

答案 0 :(得分:0)

这是一个已知问题。 Google" android片段重新排序"并且您将获得关于该主题的整页链接,包括一些解决方案。