重学安卓1-6:我的碎片很听话,你的 Fragment 有自己想法

作品简介
往期回顾专栏目录更新动态优惠政策版权须知
温馨提示:如这是第一次接触《重学安卓》,可通过上述链接快速了解《重学安卓》专栏,获取 专栏目录、试读内容、更新动态 和 发展状况。
截至目前,专栏已对 体系化文章 实施 3310 余次修订,数十位群友告诉我,受专栏启发 亦开启了写作之路。群里不定期会有小伙伴讨论适配问题、分享原创开源库 和 提供内推机会,订阅后可随时进群交流。

·

Note 2021.5.25 重要提示
阅读本文最佳时机是,您已吃过 阅读 “源码” 或 “源码分析文” 时 找不到头绪的苦
您还没吃过苦,那您先不要着急阅读本文。您得吃过苦,才会有体会。
在您吃够这方面苦后,您才有机会发现,本文正是专用于解决 “如何找到正确打开方式” 的困扰。
我们绝不通篇贴源码,而是基于广泛实践和反思,在累积过大量样本 乃至足以排除掉所有干扰信息后,点到为止揭露 Fragment 框架最核心本质,方便您理解其真实的存在意义,乃至笃信使用项目中。

前言

谈到 Android 开发,始终绕不开 Fragment。日常开发,想必或多或少都在用 “单 Activity 架构”、而页面都由 Fragment 编写,

但 Fragment 使用并非一帆风顺,在其带来一定便利同时,亦额外引入令人困扰麻烦,

故今日我们继续以 “第一性原理” 视角探寻 Fragment 来龙去脉,相信阅读后,你会对 Fragment 存在缘由、设计依据、区别、特点 有更深印象,在 “选择 Activity 还是 Fragment 来开发特定场景页面” 问题上,也更易取舍。

文章目录一览

  • Fragment 缘起和职责为何?
  • Fragment 和 Activity 返回栈区别?为何存在这区别?
  • Fragment 和 Activity 通信方式区别?为何存在这区别?
  • Fragment 生命周期为何如此设计?
  • Fragment 和 Activity 生命周期关系?
  • Fragment 和 Activity 重建及状态管理方式区别?
  • 为何导致 Fragment 重叠?
  • 为何推荐使用 DialogFragment?
  • 为何视图控制器建议用 Fragment 而非 Activity?
  • 综上
  • Note 2020.3.31 加餐:
  • Fragment 最新 API 支持 replace 回退后状态恢复
  • 后记

Fragment 缘起和职责为何?

Fragment 在 Android 3.0 被引入,最初是专用于适配平板视图。

Android 4.0 起,Fragment 被升级为手机和平板通用。

如此一来,我们便知,Fragment 的存在是为了:

  • 适配 “横竖屏场景” 需求:

例如在平板模式下显示手机布局,既不美观、也浪费空间,Fragment 的出现就能解决该问题,让 List 和 Detail 同时显现。

  • 实现代码复用:

一个 Fragment 类可以被实例化多次,也可在多个 Activity 中使用。反之,每新建一个 Activity,就要重新部署一套布局和代码逻辑,十分麻烦。

因而,更纯粹说,Fragment 的存在,是 专注于承担 “视图控制器” 责任,以分担 Activity 责任、让 Activity 更专注于 “幕后协调者” 工作。

Fragment 和 Activity 返回栈区别?为何存在这区别?

《拎清 Activity 任务和返回栈》 一文中,我们将 “任务” 和 “返回栈” 两个概念做了正确的区分,并理解了 “启动模式” 是怎么影响 Activity 与任务间的关系。

Fragment 也包含 “返回栈” 设计。

在了解 Fragment 返回栈之前,我们先来了解一下 Fragment 生存的背景:

Fragment 完全依附于 FragmentActivity 而存在,因为有且只有 FragmentActivity 直接或间接包含了与 “Fragment 管理” 相关的一系列成员,包括 FragmentController、FragmentManager 等等。

注:AppCompatActivity 是 FragmentActivity 子类,所以使用 AppCompatActivity 即代表支持 Fragment。

也因此,和 Activity 的区别在于,Fragment 的管理没有任务栈,而只有返回栈。

—— 为何如此设计?

如通过上述描述,还是不免如此发问、不能秒懂,那还是请先根据 《拎清 Activity 任务和返回栈》 做好前置功课。

我换个方式再简单解析一下:因为 Activity 是组件,组件的设计要考虑到 “跨进程通信”,故不仅被设计出任务栈管理 Activity,还设计出返回栈,用于管理来自多个 App 的 SingleTask 模式且 taskAffinity 指明过不同任务名任务。

而 Fragment 因为背靠单个 Activity,而不需要考虑 “跨进程/跨App” 问题,因而它只需返回栈。

划重点 👆👆👆

通常我们是以如上方式,将一个 Fragment 以事务的方式添加到返回栈。

事务我们在大学学习数据库时接触过,是指一组原子性的操作,也即这波操作要么全完成,要么全不完成,绝不导致烂尾现象,且完成后还可回滚到完成前现场。

很显然 Fragment 出栈,就是事务回滚。

那既然 Fragment 返回栈采用事务管理方式,Activity 管理为何不如此设计?

因为 Activity 与任务关系、任务与返回栈关系,随时可能发生变化,在栈中位置随时动态发生变化,而非 Fragment 这种单纯的进出。

划重点 👆👆👆

被 Fragment 返回栈管理的一个个对象就叫 BackStackRecord —— 是 FragmentTransaction 实现 —— 当提交 Fragment 事务时,实际上提交的就是一个个 BackStackRecord。

值得注意的是,上述提到 FragmentController,它只是直接隶属于 FragmentActivity、用于批量管理 Fragment 的一个代理,实际真正在管理 Fragment 的是 FragmentManager …… 这些后续自行顺着源码去看就行,能不贴代码我尽量不贴代码,因为动不动就贴一长串代码,十分影响阅读。

Fragment 和 Activity 通信方式区别?为何存在这区别?

上一节我们讲到,Fragment 与 Activity 在返回栈设计差异,取决于 Fragment 和 Activity 在生存环境差异。

同样的,由于生存环境差异,导致 Fragment 与 Activity,及 Fragment 之间通信,不再是组件间通信,乃至无需考虑跨进程通信、无需使用 Intent 通过 Binder 来通信,而是可以直接使用接口。

具体 可将文末《重学安卓》配套项目 clone 到本地,在 OneTestFragment 中查看,此处不作累述。

Fragment 生命周期为何如此设计?

《Activity 生命周期 3 个辟谣》 一文中,我们结合 “进程模式” 概念,介绍过 Activity 生命周期设计依据。

Fragment 生命周期同样有其设计依据。

Fragment 生命周期和 Activity 生命周期存在一定差异,并且受事务添加方式影响。

差异主要表现为,Fragment 生命周期节点相比 Activity 多了 onAttach、onCreateView、onViewCreated、onActivityCreated、onDestroyView、onDetech,而少了 onRestart。

为何要多出这些节点?主要来自 3 方面因素:
创作时间: