学习 Android(十)Fragment的生命周期

06-01 697阅读

简介

Android 的 Fragment 是一个具有自己生命周期的 可重用 UI 组件,能够在运行时灵活地添加、移除和替换,从而支持单 Activity 多界面、动态布局和响应式设计。掌握 Fragment 的生命周期有助于正确地在各个阶段执行初始化、资源绑定、状态保存与释放操作,避免内存泄漏和 UI 崩溃。

1. Fragment 生命周期核心方法

Fragment 的生命周期与 Activity 紧密关联,但包含更多与视图相关的回调:

生命周期方法触发时机用途
onAttach()Fragment 与 Activity 关联时获取 Activity 引用,初始化参数
onCreate()Fragment 首次创建时(早于视图创建)初始化非视图数据(如数据库查询)
onCreateView()创建 Fragment 的视图时加载布局文件(返回 View 对象)
onViewCreated()在 onCreateView() 执行完成后获取视图控件引用、配置 RecyclerView 等
onActivityCreated()关联的 Activity 已完成 onCreate()确保 Activity 视图就绪,执行 Activity 与 Fragment 的交互逻辑
onStart()Fragment 可见时(与 Activity 同步)更新 UI 数据
onResume()Fragment 可交互时(与 Activity 同步)启动动画、注册传感器监听
onPause()Fragment 失去焦点时(如跳转其他 Activity)停止耗时操作、保存临时数据
onStop()Fragment 不可见时释放 UI 相关资源
onDestroyView()Fragment 视图被移除时(但 Fragment 实例仍存在)清理视图绑定、取消异步任务
onDestroy()Fragment 即将被销毁时释放非视图资源
onDetach()Fragment 与 Activity 解除关联时清除 Activity 引用

2. Fragment 生命周期状态图

学习 Android(十)Fragment的生命周期

3. Fragment 生命周期示例

- app
  - src/main
    - java/com/example/fragmentdemo
      - MainActivity
      - BaseFragment
      - FragmentA
      - FragmentB
    - res/layout
      - activity_main.xml
      - fragment_a.xml
      - fragment_b.xml
  • BaseFragment

    abstract class BaseFragment : Fragment() {
        protected val TAG: String = "FragmentLifecycle"
        override fun onAttach(@NonNull context: Context) {
            super.onAttach(context)
            Log.d(TAG, "${this::class.java.simpleName} onAttach")
        }
        override fun onCreate(@Nullable savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            Log.d(TAG, "${this::class.java.simpleName} onCreate")
        }
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            Log.d(TAG, "${this::class.java.simpleName} onCreateView")
            return inflater.inflate(getLayoutId(), container, false)
        }
        override fun onViewCreated(@NonNull view: View, @Nullable savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            Log.d(TAG, "${this::class.java.simpleName} onViewCreated")
        }
        override fun onActivityCreated(@Nullable savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)
            Log.d(TAG, "${this::class.java.simpleName} onActivityCreated")
        }
        override fun onStart() {
            super.onStart()
            Log.d(TAG, "${this::class.java.simpleName} onStart")
        }
        override fun onResume() {
            super.onResume()
            Log.d(TAG, "${this::class.java.simpleName} onResume")
        }
        override fun onPause() {
            super.onPause()
            Log.d(TAG, "${this::class.java.simpleName} onPause")
        }
        override fun onStop() {
            super.onStop()
            Log.d(TAG, "${this::class.java.simpleName} onStop")
        }
        override fun onDestroyView() {
            super.onDestroyView()
            Log.d(TAG, "${this::class.java.simpleName} onDestroyView")
        }
        override fun onDestroy() {
            super.onDestroy()
            Log.d(TAG, "${this::class.java.simpleName} onDestroy")
        }
        override fun onDetach() {
            super.onDetach()
            Log.d(TAG, "${this::class.java.simpleName} onDetach")
        }
        /** 子类必须提供此方法来返回布局资源 ID */
        @LayoutRes
        protected abstract fun getLayoutId(): Int
    }
    
  • fragment_a.xml

    
        
    
    
  • fragment_b.xml

    
        
    
    ```
    • FragmentA

      class FragmentA : BaseFragment() {
          override fun getLayoutId() = R.layout.fragment_a
      }
      
    • FragmentB

      class FragmentB : BaseFragment() {
          override fun getLayoutId() = R.layout.fragment_b
      }
      
    • activity_main.xml

      
          
          
          
          
      
      
    • MainActivity

      class MainActivity : AppCompatActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_main)
              // 首次添加 FragmentA
              supportFragmentManager.beginTransaction()
                  .add(R.id.fragment_container, FragmentA())
                  .commit()
          }
          fun switchToFragmentB(view: View) {
              supportFragmentManager.beginTransaction()
                  .replace(R.id.fragment_container, FragmentB())
                  .commit()
          }
      }
      
      • 初始加载 FragmentA 的生命周期如下

        FragmentA onAttach
        FragmentA onCreate
        FragmentA onCreateView
        FragmentA onViewCreated
        FragmentA onActivityCreated
        FragmentA onStart
        FragmentA onResume
        
      • 切换 FragmentB 不加入返回栈的生命周期如下

        FragmentA onPause
        FragmentA onStop
        FragmentB onAttach
        FragmentB onCreate
        FragmentB onCreateView
        FragmentB onViewCreated
        FragmentB onActivityCreated
        FragmentB onStart
        FragmentA onDestroyView
        FragmentA onDestroy
        FragmentA onDetach
        FragmentB onResume
        
      • 切换 FragmentB 加入返回栈的生命周期如下

        fun switchToFragmentB(view: View) {
            supportFragmentManager.beginTransaction()
                .replace(R.id.fragment_container, FragmentB())
                .addToBackStack("fragmentB") // 可选:加入返回栈
                .commit()
        }
        
        // 点击切换按钮
        FragmentA onPause
        FragmentA onStop
        FragmentA onDestroyView
        FragmentB onAttach
        FragmentB onCreate
        FragmentB onCreateView
        FragmentB onViewCreated
        FragmentB onActivityCreated
        FragmentB onStart
        FragmentB onResume
        // 按返回键返回 FragmentA
        FragmentB onPause
        FragmentB onStop
        FragmentB onDestroyView
        FragmentB onDestroy
        FragmentB onDetach
        // FragmentA 重新创建视图
        FragmentA onCreateView
        FragmentA onViewCreated
        FragmentA onActivityCreated
        FragmentA onStart
        FragmentA onResume
        

        4. 示例生命周期流程图

        启动 Activity
        └── 添加 FragmentA
            ├── onAttach
            ├── onCreate
            ├── onCreateView
            ├── onViewCreated
            ├── onActivityCreated
            ├── onStart
            └── onResume
        替换为 FragmentB(无返回栈)
        ├── FragmentA.onPause
        ├── FragmentA.onStop
        ├── FragmentA.onDestroyView
        ├── FragmentA.onDestroy
        ├── FragmentA.onDetach
        └── FragmentB 完整生命周期
        替换为 FragmentB(有返回栈)
        ├── FragmentA.onPause
        ├── FragmentA.onStop
        ├── FragmentA.onDestroyView
        └── FragmentB 完整生命周期(除 onDestroy/onDetach)
        按返回键
        ├── FragmentB.onPause
        ├── FragmentB.onStop
        ├── FragmentB.onDestroyView
        ├── FragmentB.onDestroy
        ├── FragmentB.onDetach
        └── FragmentA 重建视图
            ├── onCreateView
            ├── onViewCreated
            ├── onActivityCreated
            ├── onStart
            └── onResume
        

        5. 关键结论

        • 视图生命周期
          • onCreateView 和 onDestroyView 控制视图的创建与销毁。
          • 使用 addToBackStack 后,Fragment 实例保留,但视图会被销毁。
          • 状态保留
            • 在 onSaveInstanceState() 保存数据(在 onCreate 中恢复)。
            • 视图相关数据应在 onDestroyView 中清理。
            • 最佳实践
              • 初始化数据:在 onCreate(非视图数据)或 onViewCreated(视图相关)。
              • 释放资源:
                • 视图绑定在 onDestroyView 中置空。
                • 后台线程在 onStop 中取消。
                • 避免内存泄漏:在 onDetach 中清除 Activity 引用

                  6. 常见 Fragment 面试

                  • 什么是 Fragment?它与 Activity 有何区别?

                    • Fragment 是 Android Support Library(AndroidX)提供的可重用 UI 组件,具有自己独立的生命周期,但必须托管在 Activity 中。

                    • 区别:Activity 代表一个完整的屏幕,必须在 AndroidManifest.xml 中声明;而 Fragment 只是屏幕的一部分,可以在运行时动态增删,不需在清单里注册,并支持多个 Fragment 并列显示(如平板双页布局) 。

                    • 详细描述 Fragment 的生命周期以及每个回调的作用

                      • Fragment 有独立的生命周期回调,与宿主 Activity 生命周期紧密关联,其核心顺序为:

                        onAttach() → onCreate() → onCreateView() → onViewCreated() → onStart() → onResume()
                             ▲                                    ▼
                        onPause() ← onStop() ← onDestroyView() ← onDestroy() ← onDetach()
                        
                        • onAttach(Context):Fragment 与 Activity 关联时调用,通常获取 Context 或接口回调引用。

                        • onCreate(Bundle?):进行全局变量或非视图逻辑初始化,可以调用 setRetainInstance(true) 保留 Fragment 实例。

                        • onCreateView(…):创建并返回 UI 布局,执行 inflater.inflate(...)。

                        • onViewCreated(View, Bundle?):视图创建完成后调用,安全绑定子视图和注册 LiveData 观察者 。

                        • onStart()/onResume():Fragment 可见并获得焦点,恢复动画或摄像头预览等交互逻辑。

                        • onPause()/onStop():停止动画、保存易丢失状态,释放重量级资源(如传感器、广播接收器)。

                        • onDestroyView():销毁视图层次,清理与视图绑定的引用,防止内存泄漏。

                        • onDestroy()/onDetach():彻底释放后台资源,并与 Activity 分离 。

                        • Fragment 与 Activity 之间如何传递数据?

                          • 通过 setArguments()/getArguments():在创建 Fragment 实例前,调用 fragment.arguments = Bundle().apply { putString("key", value) },在 onCreate() 中读取。此方法保证在重建时数据不会丢失。

                          • 宿主 Activity 直接调用公共方法:Activity 在 fragmentManager.findFragmentById() 后,通过类型转换调用 Fragment 的公有方法传递。

                          • 共享 ViewModel(推荐,Jetpack):Activity 和 Fragment 共享同一个 ViewModel,通过 LiveData 进行双向通信,无需显式管理 Lifecycle。

                          • ragment Result API(AndroidX 1.3+):使用 setFragmentResult()/setFragmentResultListener() 在父 Fragment 或 Activity 间传递数据,更加解耦。

                          • 如何在 Fragment 事务中使用回退栈(Back Stack),以及 add() 与 replace() 的区别?

                            • addToBackStack(tag):在调用 .beginTransaction().add(...).addToBackStack(tag).commit() 后,当前事务会被加入回退栈,用户按返回键时可撤销该事务。
                            • add():将新 Fragment 覆盖在容器上,但不移除旧 Fragment,可实现多个重叠效果,需手动 hide/show 来管理可见性 。
                            • replace():先执行 remove() 再 add(),移除容器内所有旧 Fragment,然后添加新 Fragment,常用于纯粹替换场景 。
                            • 回退行为:
                              • add() + addToBackStack():回退时会 remove 新 Fragment 并 show 旧 Fragment。
                              • replace() + addToBackStack():回退时 remove 替换的 Fragment,并重新 add 之前的 Fragment 实例 。
                              • Fragment 状态保存与 setRetainInstance(true) 的作用

                                • onSaveInstanceState(Bundle):当 Fragment 被销毁(如配置变化)前,系统会回调此方法。开发者应在其中保存 UI 状态(如滚动位置、输入内容)到 Bundle。

                                • setRetainInstance(true):设置后,在父 Activity 重建(如旋转)时,Fragment 实例不会被销毁,保留成员变量。但仍会销毁/重建视图层次;仅适用于保存非视图状态且慎用,避免与 ViewBinding 冲突。

                                • 嵌套 Fragment(Child Fragment)与 getChildFragmentManager() 的使用场景

                                  • 嵌套 Fragment:在一个 Fragment 内再承载多个子 Fragment,用于实现如选项卡、动态表单多级结构等复杂 UI。

                                  • 使用 childFragmentManager(而非 parentFragmentManager)进行事务管理,确保子 Fragment 生命周期与父 Fragment 关联,并自动在父销毁时清理子 Fragment。

                                  • Fragment 性能优化与常见坑

                                    • 避免过度嵌套:深度嵌套会增加测量与布局开销,建议扁平化布局或使用 ConstraintLayout。
                                    • 使用 View Binding / Data Binding:减少 findViewById,在 onDestroyView() 中将绑定置空避免泄漏。
                                    • 合理使用事务方式:大量 add/remove/replace 可能产生视图碎片化,考虑使用 show()/hide() 配合复用可提高效率 。
                                    • 异步加载:在 onCreateView() 只做视图膨胀,耗时操作(网络、数据库)放到 onViewCreated() 后的协程或 RxJava 中处理。
                                    • 测试:利用 FragmentScenario 在隔离环境下测试生命周期与 UI 交互,保证稳定性。

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码