当前位置: 首页 > news >正文

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

简介

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 生命周期状态图

img

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 */@LayoutResprotected abstract fun getLayoutId(): Int
    }
    
  • fragment_a.xml

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".FragmentA"><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="25sp"android:textColor="@color/black"android:text="This is Fragment A" /></FrameLayout>
    
  • fragment_b.xml

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".FragmentB"><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="25sp"android:textColor="@color/black"android:text="This is Fragment B" />
    
```
  • 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

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><!-- 切换 Fragment 的按钮 --><Buttonandroid:id="@+id/btn_switch"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="切换到 FragmentB"android:onClick="switchToFragmentB" /><!-- Fragment 容器 --><FrameLayoutandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" /></LinearLayout>
    
  • MainActivity

    class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 首次添加 FragmentAsupportFragmentManager.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 onStopFragmentB onAttach
      FragmentB onCreate
      FragmentB onCreateView
      FragmentB onViewCreated
      FragmentB onActivityCreated
      FragmentB onStartFragmentA onDestroyView
      FragmentA onDestroy
      FragmentA onDetachFragmentB onResume
      
    • 切换 FragmentB 加入返回栈的生命周期如下

      fun switchToFragmentB(view: View) {supportFragmentManager.beginTransaction().replace(R.id.fragment_container, FragmentB()).addToBackStack("fragmentB") // 可选:加入返回栈.commit()
      }
      
      // 点击切换按钮
      FragmentA onPause
      FragmentA onStop
      FragmentA onDestroyViewFragmentB 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. 关键结论

  • 视图生命周期
    • onCreateViewonDestroyView 控制视图的创建与销毁。
    • 使用 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 交互,保证稳定性。

相关文章:

  • C语言中的内存函数
  • 9-码蹄集600题基础python篇
  • 第二次中医知识问答微调
  • Java 代码生成工具:如何快速构建项目骨架?
  • 游戏盾功能与技术解析
  • 数据库表关系详解
  • Python实例题:Python实现简单画板
  • 建筑资料员考试主要考什么
  • 谷歌2025年I/O开发者大会热点总结
  • 欧拉系统安装,配置静态ip
  • SAP-ABAP:ABAP异常处理与安全工程的融合 —— 构建防注入、防泄漏、合规审计的防御性编程体系
  • SID103S/D/Q-300nA,轨至轨 CMOS 运算放大器,替代SGM8141/2/4,TP2111
  • AI应用电商篇汇总(持续补充)
  • 使用Redis的Bitmap实现了签到功能
  • RT_Thread——快速入门
  • 逆向音乐APP:Python爬虫获取音乐榜单 (1)
  • SQL语句-常用版
  • OpenCV CUDA模块图像过滤------创建一个盒式滤波器(Box Filter)函数createBoxFilter()
  • 从零开始的嵌入式学习day25
  • 时间序列预测的迁移学习
  • 专题网站建设/推广引流方法与渠道
  • dms wordpress 导入 报错/seo是什么部门
  • 泰安人才网首页/常州seo
  • aws 虚机wordpress教程/佛山百度提升优化
  • 如何查看网站的点击量/网店运营培训
  • 邯郸网站设计招聘网/官方百度app下载安装