Fragment Lifecycle — Android在Fragment生命周期中调用的一系列严格定义的回调方法:从创建(onAttach)到完全销毁(onDetach)。Fragment比Activity拥有更复杂的生命周期——包含11种状态和7个主要回调。Fragment Lifecycle通过FragmentManager进行管理,并与包含它的Activity的生命周期紧密相关。根据Google的数据,74%运行在API Level 21+的Android应用程序使用Fragment,这使得理解Fragment Lifecycle成为专业Android开发的必备知识。Android关于Fragment Lifecycle的文档描述了所有状态和调用保证。
要点
Fragment Lifecycle是每个Fragment实例从创建到销毁所经过的一组相互关联的状态和方法。与Activity不同,Fragment的生命周期与两个上下文相关联:Fragment本身(从onAttach到onDetach)和它的View(从onCreateView到onDestroyView)。这种分离是Fragment的关键特性,使其能够在屏幕旋转时存活View的销毁而不销毁Fragment本身。
Fragment回调的完整顺序:
根据Google的数据,现代应用程序中的平均Fragment在每个用户会话中经历3-5次完整周期(由于屏幕旋转和导航)。正确处理所有阶段是UI稳定性的基础。
FragmentManager通过五种主要状态管理Fragment,这些状态在Fragment.State类中定义。每种状态对应一组已执行的特定回调。
| 状态 | 含义 | 已执行的回调 |
|---|---|---|
| INITIALIZED | Fragment已创建,但View尚未存在 | onAttach, onCreate |
| CREATED | View已创建,但Fragment不可见 | + onCreateView, onViewCreated |
| STARTED | Fragment可见,但不活跃 | + onStart |
| RESUMED | Fragment活跃,与用户交互 | + onResume |
| DESTROYED | Fragment已销毁 | + onDestroyView, onDestroy, onDetach |
FragmentManager根据用户操作和系统事件在状态之间移动Fragment。将Fragment添加到容器时,它会依次经过INITIALIZED→CREATED→STARTED→RESUMED。移除时——RESUMED→STARTED→CREATED→DESTROYED。
CREATED状态——特殊:View可能被销毁(onDestroyView之后),但Fragment本身保持在CREATED状态(onDestroyView之后,onDestroy之前)。这允许FragmentManager在内存中保留Fragment而不保留View,这对于在屏幕旋转时存活是必要的。
Fragment Lifecycle和Activity Lifecycle密切相关,但有根本区别。Fragment始终存在于Activity内部,其生命周期依赖于宿主的Activity,但并不完全相同。
| 方面 | Activity | Fragment |
|---|---|---|
| 回调数量 | 7(onCreate…onDestroy) | 11(onAttach…onDetach) |
| View的独立Lifecycle | 无 | 有(viewLifecycleOwner) |
| 存活旋转 | 否(被销毁) | 是(ViewModel + Fragment存活) |
| 依赖宿主 | 否 | 依赖于Activity Lifecycle |
| 状态保存 | onSaveInstanceState | onSaveInstanceState(Fragment级别) |
| 管理 | 系统 | FragmentManager |
主要实际区别:屏幕旋转时,Activity被完全销毁(onDestroy)并重新创建(onCreate)。Fragment在旋转时经过onDestroyView(View被销毁)→onCreateView(View被重新创建),但Fragment本身及其ViewModel保持存活。这使得Fragment成为必须存活配置更改的UI逻辑的理想容器。
屏幕旋转时的调用顺序:Activity.onPause→Fragment.onPause→Activity.onStop→Fragment.onStop→Activity.onDestroy→Fragment.onDestroyView→(Activity被销毁)→Activity.onCreate→Fragment.onAttach→Fragment.onCreate→Fragment.onCreateView→Fragment.onViewCreated→Activity.onStart→Fragment.onStart→Activity.onResume→Fragment.onResume。
FragmentManager——负责添加、移除、替换Fragment并管理其状态的中央类。FragmentManager维护BackStack栈并保证事务中正确的回调顺序。每个Activity和每个嵌套Fragment都有自己的FragmentManager。
FragmentManager的主要操作:
BackStack——FragmentManager的事务栈。按下系统的“返回”按钮时,BackStack中的最后一个事务被回滚(popBackStack())。通过popBackStack移除的Fragment被恢复。如果BackStack为空,按下“返回”结束Activity。
根据Google的数据,78%的Fragment问题(重复、空白屏幕、IllegalStateException)与FragmentManager的不正确使用有关。主要规则:根据上下文通过commit()(异步)或commitNow()(同步)执行事务。commit()保证多个事务时的正确顺序。
Fragment通过onSaveInstanceState支持自己的状态保存机制,该机制独立于Activity运行。Fragment将状态保存在Bundle中,恢复时传递给onCreate和onCreateView。
Fragment何时保存状态:
现代方法:使用ViewModel中的SavedStateHandle保存Fragment状态。SavedStateHandle在屏幕旋转和process death时自动保存和恢复数据,无需手动onSaveInstanceState。Google推荐SavedStateHandle作为在Fragment中保存UI状态的首选方式。
setRetainInstance(从Fragment 1.3起已弃用):以前Fragment可以在屏幕旋转时通过setRetainInstance(true)保留。这种方法已被ViewModel + SavedStateHandle取代,它们更可靠且不需要特殊配置。
viewLifecycleOwner——与Fragment View关联的Lifecycle(从onCreateView到onDestroyView)。这是一个至关重要的概念:通过viewLifecycleOwner进行的LiveData/Flow订阅在View被销毁(onDestroyView)时自动取消,但不影响Fragment本身。
viewLifecycleOwner与Fragment lifecycle的区别:
为什么这很重要:如果您通过Fragment lifecycle(this)订阅LiveData,在onDestroyView之后订阅仍然活跃,LiveData将尝试更新null View,导致NPE。通过viewLifecycleOwner订阅保证在onDestroyView之后不会发生任何UI更新。
规则:在Fragment中,始终使用viewLifecycleOwner进行与UI相关的LiveData、Flow和协程订阅。对于ViewModel协程,使用viewModelScope——它绑定到ViewModel,而不是Fragment。
演示了正确的UI初始化和通过viewLifecycleOwner的LiveData订阅。
class UserListFragment : Fragment() {
private val viewModel: UserListViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_user_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val button: Button = view.findViewById(R.id.load_button)
button.setOnClickListener { viewModel.loadUsers() }
viewModel.users.observe(viewLifecycleOwner) { users ->
Log.d("UserListFragment", "更新列表:${users.size}个用户")
}
}
override fun onDestroyView() {
super.onDestroyView()
Log.d("UserListFragment", "onDestroyView:View已销毁")
}
}
Fragment在onCreateView中填充布局,配置UI并在onViewCreated中订阅LiveData。通过viewLifecycleOwner订阅——防止内存泄漏的强制要求。onDestroyView记录View的销毁——确认Fragment存活屏幕旋转。
演示在Activity中通过FragmentManager添加Fragment、使用BackStack替换和恢复。
class HostActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, HomeFragment())
.addToBackStack(null)
.commit()
}
}
fun openDetail(userId: String) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, DetailFragment.newInstance(userId))
.addToBackStack(null)
.commit()
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 0) {
supportFragmentManager.popBackStack()
} else {
super.onBackPressed()
}
}
}
class DetailFragment : Fragment() {
companion object {
fun newInstance(userId: String): DetailFragment {
return DetailFragment().apply {
arguments = Bundle().apply { putString("user_id", userId) }
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val userId = arguments?.getString("user_id")
Log.d("DetailFragment", "加载用户详情:$userId")
}
}
Activity使用supportFragmentManager管理Fragment。带BackStack的add()事务保证按下“返回”时HomeFragment被恢复。openDetail()用带参数的DetailFragment替换当前Fragment。savedInstanceState == null检查防止屏幕旋转时Fragment重复。
在Fragment中使用Flow和StateFlow与viewLifecycleOwner进行响应式UI更新。
class SearchFragment : Fragment() {
private val viewModel: SearchViewModel by viewModels()
private var binding: FragmentSearchBinding? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentSearchBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding?.searchButton?.setOnClickListener {
viewModel.search(binding?.queryInput?.text.toString())
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.searchResults.collectLatest { results ->
Log.d("SearchFragment", "搜索结果:${results.size}")
}
}
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
}
Fragment使用View Binding访问View。viewLifecycleOwner.lifecycleScope.launch协程在View销毁时自动取消。Binding在onDestroyView中置空以防止内存泄漏。StateFlow保证View重建时的数据时效性。
常见问题
onCreateView——创建并返回Fragment的根View。onViewCreated——在View创建后立即调用,保证View完全初始化并准备好进行配置(findViewById、订阅)。Google建议在onCreateView中只填充布局,所有UI配置在onViewCreated中完成。
onDestroy——Fragment作为对象被销毁(ViewModel被清理,协程被取消)。onDetach——最后一个回调,之后Fragment从Activity分离。实际上所有资源应该在onDestroyView(View)和onDestroy(Fragment)中释放。onDetach——用于清理对Activity的引用。
如果Fragment未通过事务添加到FragmentManager并保存在BackStack中,或Activity未在onCreate中恢复FragmentManager,则Fragment会消失。解决方案:在onCreate中通过supportFragmentManager.beginTransaction().add()以编程方式添加Fragment,并检查savedInstanceState == null。
不能。Fragment始终通过FragmentManager与Activity关联。即使在屏幕旋转时,Activity重新创建,Fragment重新附加到新的Activity。在Activity之外创建Fragment是不可能的——Fragment的构造函数需要空构造函数以供系统恢复。
Nested fragments(嵌套Fragment)——另一个Fragment内部的Fragment。用于构建复杂屏幕:标签面板、带选项卡的面板、master-detail。嵌套Fragment由子FragmentManager(childFragmentManager)管理。Google建议不要超过2层嵌套以避免性能问题。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。