马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
简介
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 生命周期状态图
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
- <?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">
- <TextView
- android: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">
- <TextView
- android: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 的按钮 -->
- <Button
- android:id="@+id/btn_switch"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="切换到 FragmentB"
- android:onClick="switchToFragmentB" />
- <!-- Fragment 容器 -->
- <FrameLayout
- android: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)
- // 首次添加 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 交互,包管稳定性。
|