弹出整个 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.
更多详情:
- 根据 Activity 状态管理器转储,我的片段仍然有其视图,但 mFragmentId 和 mContainerId 都设置为 #0。
- 我确实添加了另一个我没有在这里讨论的片段,它保留了它的实例,但它只用于保存一些数据并且没有任何视图。
支持库版本25.1.0及以上有PopBackStackImmediate bug
由于已报告此问题,您要么必须等待解决方案,要么可以将支持库版本降级到 25.0.1 并获得预期的行为。
更新
看来此错误已在支持库版本 25.3.1 中得到解决。将您的库更新到版本 25.3.1。
实际问题/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.
更多详情:
- 根据 Activity 状态管理器转储,我的片段仍然有其视图,但 mFragmentId 和 mContainerId 都设置为 #0。
- 我确实添加了另一个我没有在这里讨论的片段,它保留了它的实例,但它只用于保存一些数据并且没有任何视图。
支持库版本25.1.0及以上有PopBackStackImmediate bug 由于已报告此问题,您要么必须等待解决方案,要么可以将支持库版本降级到 25.0.1 并获得预期的行为。
更新
看来此错误已在支持库版本 25.3.1 中得到解决。将您的库更新到版本 25.3.1。