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

Fragment 全解

Fragment 不属于"四大组件"(Activity / Service / BroadcastReceiver / ContentProvider),它没有自己独立的生命周期入口,必须依附在 Activity(或另一个 Fragment)之中。但它太重要了——现代 Android 主流的"单 Activity 架构"正是建立在 Fragment 之上。

一、Fragment:可复用的"界面碎片"

在 Activity 篇 里我们打过一个比方:

Activity 是相框,Fragment 是相框里可以随时替换的照片。

Activity 是用户看到的"窗口",但一个窗口里的内容往往需要拆分复用

  • 手机上是「列表页」和「详情页」两个界面,平板上却希望它们并排显示在同一个屏幕里;
  • 一个底部导航栏 App,点击不同 Tab 切换内容,但顶部栏、底部栏始终不变。

如果一个界面就开一个 Activity,上面这些需求会非常难写。Fragment 就是为此而生:它是一段可复用的、带有自己生命周期和界面的 UI 单元,可以被组合进 Activity,也可以在运行时动态添加、替换、移除。

一个最简单的 Fragment 长这样:

classProfileFragment:Fragment(R.layout.fragment_profile){overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super.onViewCreated(view,savedInstanceState)// 在这里拿到布局里的控件,绑定数据、设置监听valnameText=view.findViewById<TextView>(R.id.name)nameText.text="张三"}}

注意:Fragment不需要AndroidManifest.xml中注册(这点和四大组件完全不同),它由宿主 Activity 在代码或布局中加载。

Fragment 与 Activity 的关系

  • 一个 Activity 可以容纳一个或多个Fragment;
  • Fragment 的生命周期完全依赖于宿主 Activity——Activity 销毁了,里面的 Fragment 也会跟着销毁;
  • 我们日常用的AppCompatActivity→ 继承自FragmentActivity,正是FragmentActivity提供了管理 Fragment 的能力;
  • Jetpack 的Navigation组件就是基于"单 Activity + 多 Fragment"架构设计的。

注意版本与依赖:现在开发应优先使用 AndroidX 的androidx.fragment.app.Fragment,而不是已废弃的平台版android.app.Fragment。本文所有内容都基于 AndroidX Fragment。


二、单 Activity 架构

早期 Android 是"一个界面一个 Activity"。但随着平板、折叠屏、大屏设备出现,这种方式越来越力不从心:

问题纯 Activity 方案Fragment 方案
平板分屏(列表 + 详情并排)难以实现,Activity 无法并排两个 Fragment 放进同一界面即可
界面复用(同一块 UI 多处使用)复制粘贴布局和逻辑写一个 Fragment 到处用
切换内容但保留外壳(底部导航)频繁启动 Activity,外壳重复一个 Activity 壳,切换 Fragment
页面间转场动画受限于 Activity 转场Fragment 事务可灵活控制动画

于是现代应用的主流架构变成了:

一个 Activity 作为"外壳" + 多个 Fragment 作为"内容页",页面跳转交给 Navigation 组件管理。

这就是单 Activity 架构(Single-Activity Architecture),也是 Google 目前推荐的做法。


三、Fragment生命周期

理解 Fragment,最核心的就是它的生命周期。它比 Activity 复杂,原因在于:

Fragment 有"两条命"——它自身的实例(Fragment 对象)和它的视图(View)是分开管理的。

这一点至关重要,后面会专门展开。先看完整的回调顺序。

3.1 创建阶段的回调顺序

从添加到 Activity,到界面显示,Fragment 依次经历:

  1. onAttach()─── Fragment 与宿主 Activity 关联,此时可以拿到Context

  2. onCreate()─── 创建 Fragment 实例,初始化非视图数据(注意:此时还没有 View)

  3. onCreateView()─── 创建并返回 Fragment 的视图(加载布局)

  4. onViewCreated()─── 视图已创建完成,在这里操作控件最安全

  5. onViewStateRestored()─── 恢复视图保存的状态(如输入框文字)

  6. onStart()─── Fragment 可见

  7. onResume()─── Fragment 到达前台,可与用户交互

    ← 用户正常使用中 →

3.2 销毁阶段的回调顺序

  1. onPause()─── 失去前台焦点
  2. onStop()─── 完全不可见
  3. onDestroyView()───销毁视图(但 Fragment 实例还在)
  4. onDestroy()─── 销毁 Fragment 实例
  5. onDetach()─── Fragment 与 Activity 解除关联

3.3 每个回调该做什么?

回调什么时候调用你该做什么
onAttach()与 Activity 关联时获取Context,做与宿主相关的初始化
onCreate()创建实例时初始化与视图无关的数据(如读取参数arguments
onCreateView()需要绘制界面时加载并返回布局(推荐用构造函数传布局 ID 替代手写此方法)
onViewCreated()视图创建完成后绑定控件、设置监听、观察 ViewModel/LiveData
onStart()即将可见注册 UI 相关监听
onResume()到达前台开启动画、请求相机/传感器
onPause()即将失去前台暂停动画、提交临时数据
onStop()完全不可见释放重量级资源
onDestroyView()视图被销毁清理对 View 的引用(如置空 binding),注销视图相关监听
onDestroy()实例被销毁释放剩余资源
onDetach()与 Activity 解除关联清理对 Context 的引用

注意:不要在onCreateView()之前(如onCreate())操作视图控件,因为那时 View 还不存在。绑定控件、设置点击事件等,统一放在onViewCreated()里最安全。


四、Fragment 的"两条命":实例 vs 视图

这是 Fragment 生命周期里最容易出 Bug的地方,必须单独讲清楚。

普通情况下 Fragment 走完整流程没问题。但有一种常见场景会让"实例还活着、视图却已经死了":把 Fragment 放进BackStack(返回栈)后,又导航到另一个 Fragment。

此时旧 Fragment 会执行到onDestroyView()——它的视图被销毁了,但 Fragment 对象本身没有销毁(还留在返回栈里等待回来)。当用户按返回键回到它时,会重新执行onCreateView()创建一个全新的视图,但onCreate()不会再走一遍。

首次进入: onCreate → onCreateView → onViewCreated → ... → onResume 被覆盖: onPause → onStop → onDestroyView ← 视图没了,实例还在 返回回来: onCreateView → onViewCreated → ... → onResume ← 重建了新视图

这带来两个实际后果:

4.1 视图引用必须及时清理(避免内存泄漏)

如果你用 ViewBinding 持有了视图引用,必须在onDestroyView()中置空,否则旧视图无法被回收:

classProfileFragment:Fragment(R.layout.fragment_profile){privatevar_binding:FragmentProfileBinding?=null// 只在视图存在期间有效privatevalbindingget()=_binding!!overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super.onViewCreated(view,savedInstanceState)_binding=FragmentProfileBinding.bind(view)binding.name.text="张三"}overridefunonDestroyView(){super.onDestroyView()_binding=null// 关键:视图销毁了,引用也要清掉}}

4.2 观察数据要用"视图的生命周期"

观察LiveData时,不要this(Fragment 的生命周期),而要用viewLifecycleOwner(视图的生命周期):

overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super.onViewCreated(view,savedInstanceState)// 正确示例:绑定到视图生命周期viewModel.user.observe(viewLifecycleOwner){user->binding.name.text=user.name}}

为什么?如果用this,当 Fragment 视图被销毁(onDestroyView)但实例仍存活时,观察者不会被移除。等数据更新时,回调里访问的却是已被销毁的旧视图,轻则内存泄漏,重则崩溃。viewLifecycleOwner会随视图一起销毁,自动解除观察。


五、FragmentManager 与事务

Activity 用管理多个 Activity;类似地,FragmentManager负责管理一个宿主里的所有 Fragment。

获取方式:

// 在 Activity 中supportFragmentManager// 在 Fragment 中管理它的子 FragmentchildFragmentManager// 在 Fragment 中获取宿主的 FragmentManagerparentFragmentManager

所有对 Fragment 的增删改,都通过一个**事务(Transaction)**完成,并且必须commit()

supportFragmentManager.commit{setReorderingAllowed(true)// 推荐开启,优化生命周期调度replace<ProfileFragment>(R.id.container)// 替换容器里的 FragmentaddToBackStack("profile")// 加入返回栈,按返回键可回退}

5.1 add / replace / remove 的区别

操作含义注意
add()往容器里添加一个 Fragment多次 add 会叠加,旧的仍在
replace()移除容器里现有 Fragment,再添加新的最常用
remove()移除指定 Fragment
show()/hide()隐藏/显示,不销毁视图适合需要保留状态的 Tab 切换

5.2 返回栈(Back Stack)

调用addToBackStack()后,这次事务会被记录到返回栈。用户按返回键时,系统会回退这次事务(撤销 replace,恢复上一个 Fragment),而不是直接退出 Activity。这正是 Fragment 能模拟"页面跳转"的关键。

提示:直接手写FragmentManager事务在简单场景没问题,但页面多、跳转复杂时,强烈建议改用Navigation 组件(见第七节),它把这些事务封装成了可视化的导航图。


六、Fragment 通信

Fragment 应该是自包含、可复用的,所以它不应该直接持有另一个 Fragment 或 Activity 的引用去调用对方方法(那样耦合太紧,复用就破坏了)。Jetpack 推荐了几种解耦的通信方式。

6.1 共享 ViewModel(同一 Activity 内,最推荐)

同一个 Activity 下的多个 Fragment,可以共享作用域为 Activity 的 ViewModel,通过它间接通信:

// 两个 Fragment 都这样获取,拿到的是同一个 ViewModel 实例privatevalsharedViewModel:SharedViewModelbyactivityViewModels()// A Fragment 写入sharedViewModel.select(item)// B Fragment 观察sharedViewModel.selectedItem.observe(viewLifecycleOwner){item->// 收到 A 的选择}

这是平板"列表 + 详情"场景的标准做法:列表 Fragment 选中某项,详情 Fragment 自动更新。

6.2 Fragment Result API(一次性结果传递)

如果只是 A → B 传一个"结果"(类似 Activity Result),用setFragmentResult/setFragmentResultListener

// 接收方(在 onCreate / onViewCreated 中注册监听)setFragmentResultListener("requestKey"){_,bundle->valresult=bundle.getString("data")}// 发送方setFragmentResult("requestKey",bundleOf("data"to"hello"))

6.3 与宿主 Activity 通信

Fragment 需要通知 Activity 时,优先用共享 ViewModel;轻量场景也可以让 Activity 实现一个接口,Fragment 在onAttach()时拿到回调对象。但接口回调方式耦合较高,新代码更推荐 ViewModel 方案。


七、Navigation 组件

手写事务和返回栈在复杂应用里容易出错。JetpackNavigation把这些封装成了一张可视化的导航图(Nav Graph)

  • NavGraph:一张 XML(或 Compose DSL)图,描述有哪些目的地(Fragment)以及它们之间怎么跳;
  • NavHostFragment:放在 Activity 布局里的"容器",所有 Fragment 在此显示;
  • NavController:负责执行跳转、管理返回栈。
// 在 Fragment 中跳转到详情页,并安全地传参findNavController().navigate(HomeFragmentDirections.actionHomeToDetail(itemId=42))

Navigation 的优势:

  • 类型安全传参(Safe Args 插件,编译期检查参数);
  • 自动处理返回栈和返回键;
  • 统一管理转场动画、深层链接(Deep Link);
  • 与底部导航栏、抽屉菜单一键集成。

现状提示:在 Jetpack Compose 中,导航的主体已逐渐变成Navigation Compose(直接在可组合函数之间导航,不再需要 Fragment)。但只要项目还使用传统 View 体系或 Fragment,“Navigation + Fragment” 仍是主流且完全推荐的方案。


八、几种特殊的 Fragment

类型用途
DialogFragment用 Fragment 的方式实现对话框,能正确处理屏幕旋转,推荐替代直接 new 一个Dialog
BottomSheetDialogFragment从底部弹出的面板(来自 Material 库)
PreferenceFragmentCompat快速搭建"设置页",配合 XML 自动生成设置项
NavHostFragmentNavigation 组件的容器 Fragment

参考来源:

  • Android 官方文档 - Fragments
  • Fragment 生命周期
  • 在 Fragment 之间通信
  • Navigation 组件
http://www.jsqmd.com/news/961130/

相关文章:

  • Codeforces胡萝卜插件:3分钟掌握实时评级预测的终极指南
  • Sketch MeaXure:从设计标注到规范生成的企业级技术实现与工作流优化
  • 别再为版本头疼!手把手教你让Carsim 2020.0 Pro与任意版本MATLAB(如R2015a/R2016b)成功联调
  • 保姆级教程:用Synopsys ICC从零搭建RISC_CHIP物理设计环境(含.synopsys_dc_setup配置详解)
  • 2026年6月 | 升降儿童学习桌TOP8品牌推荐 - 资讯焦点
  • 盲盒定制开发新方向:主播福房互动生态方案 - 壹软科技
  • 双时钟FIFO实现跨时钟域数据安全传输
  • Godot资源解包终极指南:5分钟学会提取PCK游戏文件
  • 深伪欺诈实战防御:语音克隆、视频驱动与多模态验证
  • 真实聊聊:AI 写代码到底能省多少时间?我踩过的坑与用法
  • 最后72小时,92%考生仍用Excel填志愿——而顶尖高中早已部署AI志愿协同作战系统(附可落地的轻量级部署方案)
  • 抖音下载器完整指南:免费无水印批量下载抖音视频
  • Halcon HSmartWindowControl避坑指南:为什么DrawRectangle1失效了?手把手教你用HDrawingObject正确创建ROI
  • 2026淄博装修避坑指南|如何客观判断全屋定制品牌口碑与实力 - 资讯焦点
  • 济南奢侈品回收指南:新手小白必看,添价收资质齐全办事高效 - 薛定谔的梨花猫
  • 生产级机器学习系统四大支柱:可观测性、弹性、可验证性与可治理性
  • Claude Mythos:AI安全智能体的范式跃迁与攻防新边界
  • 2026最新诚信优选东营主城东城西城新区开发区黄金回收白银回收铂金回收彩金回收靠谱门店TOP6排行榜加联系方式推荐 - 余生黄金回收
  • 如何零基础搞定E-Hentai画廊下载?5个实用技巧让你轻松收藏
  • 2026年汕尾白蚁防治/除虫灭鼠/四害消杀专业机构怎么选? - 优质品牌推荐商
  • 大同手表回收包包回收哪家店铺靠谱价格高?26年甄选top榜店铺排行推荐 - 莘州文化
  • 2026年7款国内免费AI生图工具推荐,从小白到设计师都能用
  • 海南陵楠贸易:陵水县工地二手材料回收公司 - LYL仔仔
  • AI与平面设计厂家怎么选?设计行业的未来?
  • 2026最新诚信优选东营全市全域黄金回收白银回收铂金回收彩金回收靠谱门店TOP6排行榜加联系方式推荐 - 余生黄金回收
  • ThinkPad风扇终极控制指南:TPFanCtrl2让你的笔记本静音又高效
  • Mythos:首个可工程化漏洞挖掘流水线的AI安全范式
  • SketchUp STL插件:打破数字设计与3D打印的最后壁垒
  • 【慕伏白】Codex 使用建议
  • Kalb-Ramond引力中的黑洞热力学与洛伦兹破缺效应