弹出整个 FragmentManager BackStack 时未呈现初始片段

Initial Fragment not rendered when popping entire FragmentManager BackStack

实际问题/TL;DR:除非使用一种我认为是 hack 的方式,否则我不能用一个单一的方法将 activity 的整个后栈弹出到 return 到我的初始状态在 onCreate() 期间添加的片段。片段出现在 Activity 状态管理器转储中,但不可见,让我的屏幕一片空白。

我今天遇到了这个问题,主要是想了解这是由错误引起的还是我对 FragmentManager 的 BackStack 的误解引起的。我想确保我没有滥用 Fragments 或在不稳定的 API 基础上构建。

我有一个 activity,它本质上提供了一个下降的 "tree" 导航作为按钮网格,其中每个按钮打开一个子网格(例如,具有更多按钮的子类别)或一些自定义形式。表格的内容无关紧要,但希望用户以各种顺序重复填写。

我使用支持库 (support-v4:25.1.1) 中的片段,每当需要新的 "screen" 时(对于表单或子网格),它将使用事务添加在 activity 的 FragmentManager 上类似于:

/* adding a new screen, going further down our nav tree */
fragmentManager
            .beginTransaction()
            .addToBackStack("...")
            .replace(R.id.container, newFragment)
            .commit();

除了我的 activity 的初始状态设置外,每个交易看起来都是这样,它添加初始 "root grid" 片段而不将交易添加到后台状态。

/* adding the initial fragment during the first execution of activity's onCreate(). */
fragmentManager
            .beginTransaction()
            .replace(R.id.container, rootFragment)
            .commit();

我在这里发帖的原因是我在尝试弹出整个 BackStack 时遇到了一个非常奇怪的行为,它应该让用户回到 activity 的初始状态,它具有根网格(在上面的代码中添加的那个)。几乎我尝试过的每一种技术都能有效地清除后台堆栈,但会留下一个空屏幕,而不是我最初的主菜单网格。在查看了此处的多个问题和文档之后,我尝试了多种解决方案,但只有这个看似黑客的解决方案有效:

int remainingEntries = fragmentManager.getBackStackEntryCount();
while (remainingEntries-- > 0) {
    fragmentManager.popBackStackImmediate();
}

我说这似乎是一个 hack,因为它需要我立即(同步)弹出任意数量的后台条目以到达根目录,而根据我的理解,它应该是可以通过单个异步方法调用来做到这一点:

fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

或者正如我在这里看到的那样:

int id = fragmentManager.getBackStackEntryAt(0).getId();
fragmentManager.popBackStack(id, FragmentManager.POP_BACK_STACK_INCLUSIVE);

这只是根片段的问题,可能是因为将它添加到视图的事务没有添加到后台堆栈,因为这会导致在用户按下后退按钮时显示额外的空白屏幕关闭 activity.

更多详情:

支持库版本25.1.0及以上有PopBackStackImmediate bug 由于已报告此问题,您要么必须等待解决方案,要么可以将支持库版本降级到 25.0.1 并获得预期的行为。

更新

看来此错误已在支持库版本 25.3.1 中得到解决。将您的库更新到版本 25.3.1。