一、Fragment 生命周期框架

Fragment 生命周期包含两个相互关联但又独立的周期:

  1. Fragment 实例生命周期 - 控制 Fragment 对象本身
  2. 视图生命周期 - 控制 Fragment 的 UI 组件
// Fragment 生命周期完整流程
onAttach()

onCreate()

onCreateView()    ←─ 视图生命周期开始

onViewCreated()

onActivityCreated()  // Deprecated in API 28

onStart()

onResume()
// 用户交互中
onPause()

onStop()

onDestroyView()   ←─ 视图生命周期结束

onDestroy()

onDetach()

二、生命周期方法详解

1. 实例绑定与初始化

onAttach(Context)

override fun onAttach(context: Context) {
    super.onAttach(context)
    // Fragment 与宿主 Activity 建立关联
    // 此时可以安全地获取 Activity 引用
    val activity = requireActivity()
}
  • 在 Fragment 与 Activity 建立关联时调用
  • 获取 Context 引用,用于后续的资源访问
  • 此时 Fragment 被添加到 FragmentManager

onCreate(Bundle?)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 初始化非 UI 相关的组件
    // 恢复保存的状态
    val savedData = savedInstanceState?.getString("key")
}
  • Fragment 实例初始化
  • 执行数据恢复和初始化逻辑
  • 适合初始化 ViewModel、数据源等
  • 此时视图尚未创建

2. 视图创建与管理

onCreateView() - 核心视图创建方法

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
        ): View? {
    // 创建并返回 Fragment 的视图层级
    // container 是 Fragment 的父容器(通常为 FrameLayout)
    // false 表示不立即添加到容器
    return inflater.inflate(R.layout.fragment_layout, container, false)
}
  • 负责创建 Fragment 的 UI
  • 必须返回 View 对象或 null(无 UI)
  • 多次调用:配置变更、导航返回时

onViewCreated() - 视图初始化完成

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // 视图创建完成,可以安全访问 UI 组件
    val textView = view.findViewById<TextView>(R.id.text_view)
    textView.text = "Hello Fragment"
}
  • 视图层级已完全创建
  • 执行视图相关的初始化逻辑
  • 设置监听器、配置 Adapter 等

onActivityCreated() (已废弃)

  • 在 API 28 及以上废弃
  • 原本用于确保 Activity 视图创建完成
  • 现使用 onViewCreated() 替代

简单说明

class MyFragment : Fragment() {
    
    private lateinit var textView: TextView
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 1. 此时还没有视图,不能操作UI
        // 可以初始化数据
    }
    
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?): View {
        // 2. 创建视图,但不添加到container
        val view = inflater.inflate(R.layout.fragment_layout, container, false)
        return view
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 3. 视图已创建,可以安全地查找和操作
        textView = view.findViewById(R.id.text_view)
        textView.text = "Hello Fragment"
    }
}

Q:Fragment的onCreateView()类似于Activity的setContentView()吗?

A:不是的,这里有一个重要的概念区别。Fragment 要比 Activity 灵活很多,Fragment 不是内容,而是内容的容器和管理器。负责:管理一组 UI 组件(按钮、列表、文本等);处理这些 UI 的生命周期;响应用户交互;管理状态。

  • Fragment = 控制器 + 生命周期管理器
  • Fragment 的视图 = 实际显示的内容

Fragment 可以重新创建它的视图,而 Fragment 实例本身保持不变

场景1:Fragment A → Fragment B → 返回 Fragment A

时间线:
1. 打开 Fragment A
   - Fragment A onCreate()      ← 一次
   - Fragment A onCreateView()  ← 第一次
 
2. 导航到 Fragment B
   - Fragment A onDestroyView() ← 视图销毁,实例还在
   - Fragment B onCreate()
   - Fragment B onCreateView()
 
3. 按返回键回到 Fragment A
   - Fragment B 销毁
   - Fragment A onCreateView()  ← 第二次!重新创建视图
// 场景:Fragment 在返回栈中,用户按返回键回到这个 Fragment
class MyFragment : Fragment() {
    private var count = 0  // 实例变量,Fragment 存在就一直存在
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 这里只在 Fragment 创建时调用一次
        Log.d("Lifecycle", "onCreate called")
    }
    
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?): View {
        count++
        Log.d("Lifecycle", "onCreateView called 第${count}次")
        // 每次返回这个 Fragment 时,都会重新创建视图
        return inflater.inflate(R.layout.my_fragment, container, false)
    }
}

Q:FragmentA → FragmentB,实例销毁吗?

A:看情况!取决于你是否添加到返回栈

// 情况1:添加到返回栈 → 实例不销毁,只销毁视图
supportFragmentManager.beginTransaction()
    .replace(R.id.container, FragmentB())
    .addToBackStack("fragmentA")  // 关键:添加到返回栈
    .commit()
 
// 生命周期:
// FragmentA: onPause() → onStop() → onDestroyView()
// 实例保留,视图销毁
 
// 情况2:不添加到返回栈 → 实例销毁
supportFragmentManager.beginTransaction()
    .replace(R.id.container, FragmentB())
// 不调用 addToBackStack
    .commit()
 
// 生命周期:
// FragmentA: onPause() → onStop() → onDestroyView() → onDestroy() → onDetach()
// 实例和视图都销毁

Q:Fragment 返回栈到底是什么?

Fragment 返回栈 = 操作记录的回滚栈。栈里存的不是 Fragment 实例,而是操作记录!

// 示例流程:
// 第1步:添加 FragmentA
supportFragmentManager.beginTransaction()
    .add(R.id.container, FragmentA())
    .addToBackStack("addA")  // 记录"添加A"的操作
    .commit()
 
// 栈内容:[添加FragmentA]
 
// 第2步:替换为 FragmentB
supportFragmentManager.beginTransaction()
    .replace(R.id.container, FragmentB())
    .addToBackStack("replaceWithB")  // 记录"用B替换"的操作
    .commit()
 
// 栈内容:[添加FragmentA] ← [用B替换] ← 栈顶
// 当前显示:FragmentB
 
// 第3步:用户按返回键
// 系统:弹出栈顶记录 [用B替换]
// 执行反向操作:移除B,恢复A
// 当前显示:FragmentA
// 栈内容:[添加FragmentA]

Q:addToBackStack 是干什么的?

Q:Activity 的栈和 Fragment 的返回栈什么区别?

完全不同!这是关键区别

// Activity 栈(系统管理,每个应用一个)
// 启动 ActivityB:
startActivity(Intent(this, ActivityB::class.java))
 
// 栈状态:
// 栈底:[ActivityA] → [ActivityB] ← 栈顶(当前显示)
// 按返回键:ActivityB finish(),显示 ActivityA
// Fragment 返回栈(每个 Activity 都有自己的 Fragment 返回栈)
// 显示 FragmentB(添加到返回栈):
supportFragmentManager.beginTransaction()
    .replace(R.id.container, FragmentB())
    .addToBackStack("fragmentA")
    .commit()
 
// 栈状态:
// Activity 的 FragmentManager 内部有一个栈
// 栈顶:FragmentB 的显示操作
// 栈底:FragmentA 的初始添加操作
// 按返回键:弹出栈顶操作(回到 FragmentA)

3. 可见性状态管理

onStart()

override fun onStart() {
    super.onStart()
    // Fragment 对用户可见
    // 适合执行需要与 UI 同步的初始化
}

onResume()

override fun onResume() {
    super.onResume()
    // Fragment 可交互
    // 恢复动画、传感器、摄像头等
}

onPause()

override fun onPause() {
    super.onPause()
    // Fragment 失去交互焦点
    // 保存临时数据,暂停耗时操作
}

onStop()

override fun onStop() {
    super.onStop()
    // Fragment 完全不可见
    // 释放 UI 相关资源
}

4. 销毁阶段

onDestroyView() - 关键分离点

override fun onDestroyView() {
    super.onDestroyView()
    // Fragment 视图被移除
    // 但 Fragment 实例可能仍存在
    // 必须在此清理所有视图引用
}
  • 核心特性:Fragment 可以独立于视图存在
  • 调用场景:
    • Fragment 被替换但保留在返回栈
    • 配置变更(旋转屏幕)
    • Activity 重建

onDestroy()

override fun onDestroy() {
    super.onDestroy()
    // Fragment 实例即将销毁
    // 清理所有资源
}

onDetach()

override fun onDetach() {
    super.onDetach()
    // Fragment 与 Activity 断开连接
    // 不能再访问 Activity 引用
}

三、生命周期状态迁移

状态迁移场景分析

场景1:Fragment 替换(A → B)

Fragment A: 
  onPause() → onStop() → onDestroyView()
  // 实例保留在内存中
 
Fragment B:
  onCreate() → onCreateView() → onViewCreated() → 
  onStart() → onResume()

场景2:配置变更(屏幕旋转)

// 旧实例销毁
onPause() → onStop() → onDestroyView() → 
onDestroy() → onDetach()
 
// 新实例创建
onAttach() → onCreate() → onCreateView() → 
onViewCreated() → onStart() → onResume()

场景3:添加到返回栈

// 将 Fragment 添加到返回栈
fragmentTransaction.replace(R.id.container, fragment)
fragmentTransaction.addToBackStack("tag")
fragmentTransaction.commit()
 
// 此时生命周期
onPause() → onStop() → onDestroyView()
// 实例保留

四、关键概念:视图与实例的分离

Fragment 的状态矩阵

状态实例存在视图存在可见可交互
活跃
暂停
停止
视图销毁
完全销毁

视图销毁但实例存活的场景

  1. 返回栈导航
// Fragment 进入返回栈时
supportFragmentManager.beginTransaction()
    .replace(R.id.container, fragmentB)
    .addToBackStack(null)  // FragmentA 进入返回栈
    .commit()
// FragmentA: 视图销毁,实例保留
  1. ViewPager 中的非当前页
// ViewPager 只保持相邻 Fragment 的视图
// 非当前页的 Fragment 视图被销毁
viewPager.adapter = FragmentPagerAdapter(
    listOf(fragment1, fragment2, fragment3)
)
// fragment2 当前显示,fragment1 和 fragment3 视图可能被销毁
  1. 配置变更处理
// 在 onCreate() 中检查 savedInstanceState
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    if (savedInstanceState != null) {
        // 配置变更重建,之前的状态已保存
    }
}

五、生命周期感知的数据管理

1. 数据初始化时机

class DataFragment : Fragment() {
 
    // 1. 非 UI 数据:在 onCreate 初始化
    private lateinit var repository: DataRepository
 
    // 2. UI 相关数据:在 onViewCreated 初始化
    private lateinit var adapter: RecyclerViewAdapter
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        repository = DataRepository()  // 非 UI 初始化
    }
 
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        adapter = RecyclerViewAdapter()  // UI 相关初始化
    }
}

2. 状态保存与恢复

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    // 保存状态到 Bundle
    outState.putString("key", importantData)
}
 
override fun onViewStateRestored(savedInstanceState: Bundle?) {
    super.onViewStateRestored(savedInstanceState)
    // 恢复状态
    importantData = savedInstanceState?.getString("key")
}

3. 视图生命周期感知的观察者

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
 
    // 使用 viewLifecycleOwner 确保观察者随视图销毁而清理
    viewModel.liveData.observe(viewLifecycleOwner) { data ->
        updateUI(data)
    }
}

六、实践模式与常见问题

正确模式:分离实例与视图逻辑

class ProperFragment : Fragment() {
 
    // 实例级别数据
    private val viewModel: MyViewModel by viewModels()
    private lateinit var dataSource: DataSource
 
    // 视图级别数据
    private var recyclerView: RecyclerView? = null
    private var adapter: MyAdapter? = null
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 初始化实例数据
        dataSource = DataSource(requireContext())
    }
 
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?): View {
        return inflater.inflate(R.layout.fragment_proper, container, false)
    }
 
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 初始化视图组件
        recyclerView = view.findViewById(R.id.recycler_view)
        adapter = MyAdapter()
        recyclerView?.adapter = adapter
    }
 
    override fun onDestroyView() {
        // 清理视图引用
        recyclerView?.adapter = null
        recyclerView = null
        adapter = null
        super.onDestroyView()
    }
 
    override fun onDestroy() {
        // 清理实例数据
        dataSource.close()
        super.onDestroy()
    }
}

常见错误模式

class LeakyFragment : Fragment() {
 
    // 错误:持有视图引用但未在 onDestroyView 中清理
    private lateinit var heavyView: HeavyCustomView
 
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        heavyView = view.findViewById(R.id.heavy_view)
        heavyView.startAnimation()  // 持有强引用
    }
 
    // 缺少 onDestroyView() 清理
    // 当 Fragment 进入返回栈时:
    // - heavyView 持有已销毁视图的引用
    // - 内存泄漏!
}

七、生命周期流程图解

创建流程:
onAttach()           ← 绑定到 Activity

onCreate()           ← 实例初始化

onCreateView()       ← 创建视图

onViewCreated()      ← 视图初始化

onStart()            ← 可见

onResume()           ← 可交互
 
销毁流程:
onPause()            ← 失去交互

onStop()             ← 不可见

onDestroyView()      ← 视图销毁 ← 关键点!

onDestroy()          ← 实例销毁

onDetach()           ← 解除绑定

八、核心要点总结

  1. Fragment 生命周期包含两个层级:实例生命周期和视图生命周期
  2. onDestroyView()是分离点:Fragment 可以在没有视图的情况下存在
  3. 视图引用必须在onDestroyView()中清理:避免内存泄漏
  4. 配置变更会触发完整重建:通过 savedInstanceState 保持状态
  5. 返回栈中的 Fragment 保留实例但销毁视图:理解这种半销毁状态
  6. 使用viewLifecycleOwner管理 UI 相关操作:自动处理生命周期
    这种设计让 Fragment 能够灵活地适应动态 UI 组合、配置变更和导航场景,是现代 Android 架构的基石。

更新: 2026-01-15 17:47:51
原文: https://www.yuque.com/dongpozhouzi-mshe3/zhm85g/lp8bgkug8gknk7f4


相关笔记