Fragment的故事
目次
Fragment 在原生 Android 开发中一直占有一席之地。像 ViewPager2
、Dialog
都依赖 Fragment 来实现。虽然在实现底部导航(Bottom Navigation)时,ViewPager2
配合 Fragment 有一些小坑,但这并不影响 Fragment 在 Android 体系中的地位。
既然 Fragment 这么重要,就有必要深入了解它的奥秘。这篇文章就是一次探索。
联系 #
Fragment 的 add
、replace
、remove
、show
、hide
等操作,全部依赖 FragmentManager
。要理解 Fragment,绕不开 FragmentManager。

上图展示了 Activity 与 FragmentManager 的关系。FragmentActivity
通过 FragmentController
来更新 Fragment 状态,也会依赖 FragmentHostCallback
来获取宿主信息(例如 Fragment 数量等)。
接下来看看 FragmentHostCallback
。它其实是一个泛型类,泛型参数 <E>
一般代表宿主类型(通常是 Activity)。它本身并不对泛型做具体逻辑处理,而是充当桥梁——比如 Fragment 在获取 LayoutInflater
时需要一个 Context,这里传入的就是 Activity;Fragment 启动 Activity 的本质,也是通过宿主提供的方法来完成的。
再说大家最熟悉的 FragmentManager
。
- 早期获取方式是
getFragmentManager()
,对应android.app.Fragment
,现已废弃。 - 现在统一推荐
getSupportFragmentManager()
,来自 AndroidX 的FragmentActivity
,对应androidx.fragment.app.Fragment
。
所以,不是“官方只是标记废弃”,而是 AndroidX 迁移之后,旧版被弃用,新版才是维护方向。
在日常开发中,我们最常用的就是 add
、replace
、remove
等方法。但实际上,FragmentManager 还负责:
- 管理 Fragment 的生命周期更新
- 保存和恢复状态
- 权限请求、画中画支持
- Activity/Fragment 重建时的恢复
真正的核心远不止几个增删操作。
FragmentTransaction #
我们以一个常见的例子为起点:
|
|
这里 beginTransaction()
会先创建一个 FragmentTransaction
实例。这个实例可以收集多个操作(Op),最后通过 commit
一次性提交。
add
、replace
、remove
等方法本质上都会封装成一个个 Op
,记录操作类型和对应的 Fragment。真正执行是在调用 commit
系列方法时。
commit 系列方法 #
几个方法的区别如下:
commit() 把事务加入队列,稍后在主线程安全时异步执行。如果此时状态已经保存(比如在
onSaveInstanceState
之后),会抛出异常。commitAllowingStateLoss() 与
commit()
类似,但不会因为状态已保存而报错,可能导致状态丢失。commitNow() 立即执行事务,且会强制在所有挂起的异步事务之前完成。但它不允许再提交异步事务,否则会冲突。
commitNowAllowingStateLoss() 同上,只是允许在已保存状态后执行,可能造成状态丢失。
这样看下来,Fragment 的背后其实是一套完整的状态机,由 FragmentManager
统筹调度,FragmentHostCallback
作为宿主桥梁,FragmentTransaction
负责操作封装。我们日常写的一行 add()
,实际上都在这套复杂机制中被逐步拆解和执行。