用户通过系统返回按钮导航回去的一组页面,在开发中被称为返回栈 (back stack)。多返回栈即一堆 "返回栈",对多返回栈的支持是在 Navigation 2.4.0-alpha01 和 Fragment 1.4.0-alpha01 中开始的。本文将为您展开多返回栈的技术详解。
Navigation 2.4.0-alpha01
https://developer.android.google.cn/jetpack/androidx/releases/navigation#2.4.0-alpha01Fragment 1.4.0-alpha01
https://developer.android.google.cn/jetpack/androidx/releases/fragment#1.4.0-alpha01
系统返回按钮的乐趣
无论您在使用 Android 全新的手势导航还是传统的导航栏,用户的 "返回" 操作是 Android 用户体验中关键的一环,把握好返回功能的设计可以使应用更加贴近整个生态系统。
在最简单的应用场景中,系统返回按钮仅仅 finish 您的 Activity。在过去您可能需要覆写 Activity 的 onBackPressed() 方法来自定义返回操作,而在 2021 年您无需再这样操作。我们已经在 OnBackPressedDispatcher 中提供了针对自定义返回导航的 API。实际上这与 FragmentManager 和 NavController 中已经添加的 API 相同。
OnBackPressedDispatcher
https://developer.android.google.cn/reference/androidx/activity/OnBackPressedDispatcher针对自定义返回导航的 API
https://developer.android.google.cn/guide/navigation/navigation-custom-backFragmentManager
https://developer.android.google.cn/reference/androidx/fragment/app/FragmentManagerNavController
https://developer.android.google.cn/reference/kotlin/androidx/navigation/NavController
这意味着当您使用 Fragments 或 Navigation 时,它们会通过 OnBackPressedDispatcher 来确保您调用了它们返回栈的 API,系统的返回按钮会将您推入返回栈的页面逐层返回。
多返回栈不会改变这个基本逻辑。系统的返回按钮仍然是一个单向指令 —— "返回"。这对多返回栈 API 的实现机制有深远影响。
Fragment 中的多返回栈
在 surface 层级,对于多返回栈的支持貌似很直接,但其实需要额外解释一下 "Fragment 返回栈" 到底是什么。FragmentManager 的返回栈其实包含的不是 Fragment,而是由 Fragment 事务组成的。更准确地说,是由那些调用了 addToBackStack(String name) API 的事务组成的。
多返回栈的支持
https://developer.android.google.cn/guide/fragments/fragmentmanager#multiple-back-stacksaddToBackStack(String name)
https://developer.android.google.cn/reference/androidx/fragment/app/FragmentTransaction#addToBackStack(java.lang.String)
这就意味着当您调用 commit() 提交了一个调用过 addToBackStack() 方法的 Fragment 事务时,FragmentManager 会执行所有您在事务中所指定的操作 (比如替换操作),从而将每个 Fragment 转换为预期的状态。然后 FragmentManager 会将该事务作为它返回栈的一部分。
当您调用 popBackStack() 方法时 (无论是直接调用,还是通过系统返回键以 FragmentManager 内部机制调用),Fragment 返回栈的最上层事务会从栈中弹出 -- 比如新添加的 Fragment 会被移除,隐藏的 Fragment 会显示。这会使得 FragmentManager 恢复到最初提交 Fragment 事务之前的状态。
作者注: 这里有一个非常重要的事情需要大家注意,在同一个 FragmentManager 中绝对不应该将含有 addToBackStack() 的事务和不含的事务混在一起: 返回栈的事务无法察觉返回栈之外的 Fragment 事务的修改 —— 当您从堆栈弹出一个非常不确定的元素时,这些事务从下层替换出来的时候会撤销之前未添加到返回栈的修改。
也就是说 popBackStack() 变成了销毁操作: 任何已添加的 Fragment 在事务被弹出的时候都会丢失它的状态。换言之,您会失去视图的状态,任何所保存的实例状态 (Saved Instance State)&#x