
Jetpack 之前:Support Library 的混沌年代
2018 年之前,Google 发布 Android 依赖库的方式基本上就是乱七八糟,各管各的。在这个时代,Google 提供的依赖库主要有三个问题:
问题一:Support Library 定位不清
最早的 Support Library 只有一个目的:让新 API 能在旧系统上跑。所以命名很直接:
- android.support.v4 --- 兼容 API 4+
- android.support.v7 --- 兼容 API 7+
- android.support.v13 --- 兼容 API 13+
不过问题也来了:support-v4 随着版本迭代塞进了大量跟"API 4 兼容"毫无关系的东西(Fragment、Loader、ViewPager、NotificationCompat......),变成了一个巨型垃圾桶。support-v7 里的 appcompat 是所有人都要用的,但它依赖 v4,于是你的依赖树里永远纠缠着这两个包。
更混乱的是后来添加的各种乱七八糟的包:
support-v7-appcompat
support-v7-recyclerview
support-v7-cardview
support-v7-palette
support-design
support-customtabs
support-annotations
support-media-compat
support-fragment
support-core-ui
support-core-utils
......
它们版本号不统一,内部依赖项的版本号就更不可能统一了。例如 support-v7-appcompat 是 26.1.0,support-design 也是 26.1.0,但它们的内部依赖可能指向不同版本的 support-v4,Gradle 依赖解析天天打架。因此开发者最常做的事之一就是 exclude group: 'com.android.support' 排除冲突传递依赖。
问题二:Google 缺乏统一架构
2017 年之前,Google 对 Android 应用架构没有任何官方立场。或者说,Google 并不觉得需要给 Android APP 设立一个官方的架构标准,他们觉得这些工作应该由开发者来完成,而不是 Google。
在这个时候,官方文档和示例代码基本都以一个 Activity 作为入口:
java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 网络请求直接写在 Activity 里
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 解析 JSON 也在这里
// 操作数据库也在这里
// 更新 UI 也在这里
// 全部揉在一起
}
}
所有逻辑塞进 Activity,没有分层,没有架构指导。社区里 MVP、MVVM、MVI 各种架构满天飞,Retrofit、RxJava、Dagger 等各种库的组合使用成为主流,但这些全都不是 Google 的方案。
问题三:库与库之间没有统一设计
前面说到这个时期 Google 的库都是各自为战,每个库都是独立团队做的,设计风格、API 规范、包名规则各不相同,例如下面都是 Android 开发常用的库:
| 库 | 包名 | 设计风格 |
|---|---|---|
| AppCompat | android.support.v7.app | 兼容层 |
| RecyclerView | android.support.v7.widget | 独立组件 |
| Dagger 2 | dagger.* | APT(最初由 Square 发起,后由 Google 主导维护) |
| Gson | com.google.gson | 完全独立的 Java 库 |
| Play Services | com.google.android.gms | 另一个巨型依赖黑洞 |
没有统一的架构理念,没有统一的生命周期处理方式,没有统一的数据流方案。每个库各自解决各自的问题,开发者自己拼装。
为什么要引入 Jetpack
随着 Android 依赖库的无序混乱地发展,Google 发现有必要标准化 Android 应用开发架构,基于以下几点原因,Google 逐步推出了 Jetpack。
直接原因:Support Library 不可收拾了
到 2017 年,Support Library 的问题已经严重到 Google 自己都受不了:
- 包名语义完全失真:v4 里的东西跟 API 4 毫无关系,v7 也不是为了 API 7
- 依赖地狱:不同 support 库之间的版本冲突是 Android 开发者的日常
- 增量更新困难:改一个库可能影响一堆其他库,发版复杂
Google 需要一个干净的重新开始。AndroidX 迁移就是这个重新开始的技术基础------把 android.support.* 全部搬到 androidx.* 命名空间下,彻底脱离历史包袱。
战略原因:Google 需要架构话语权
在 2017 年之前,Android 社区的架构实践走在了 Google 前面。Retrofit(Square)、RxJava、Dagger 2、MVP/MVVM 模式------全都是社区驱动的。Google 作为平台方,对开发者怎么写 Android 应用几乎没有影响力。 这在 iOS 那边不可想象------Apple 有明确的架构指导,有第一方的网络库、数据库、UI 框架。Android 开发者却在用一堆第三方库拼装应用。
因此,Google 需要:
- 统一的架构主张------告诉开发者"应该这样写 Android 应用"
- 第一方解决方案------取代第三方库拼装的现状
- 一致的 API 设计语言------让不同库之间能无缝配合
技术原因:生命周期问题必须系统性解决
Activity/Fragment 生命周期带来的问题到了非解决不可的地步:
- 配置变更导致的状态丢失
- 异步操作在 Activity 销毁后还在执行(崩溃、泄漏)
- Fragment 生命周期与 Activity 生命周期的交错混乱
- 没有标准的状态保存/恢复机制
这些问题不可能靠单个库解决,需要一个基础设施层,让所有上层组件都能感知生命周期。
Jetpack 的历史
从上面能看到,Jetpack 本质上是一套由 Google 官方维护的 Android 开发组件集合。它不仅仅是几个库,而是一套统一的应用开发基础设施,用于解决 Android 长期以来的兼容性、生命周期、架构与 UI 开发问题。
然而其发展并不是一蹴而就的,Jetpack 里面那么多依赖库基本都是慢慢加入和升级,才形成了现在 Jetpack 库。
前奏:Architecture Components(2017)
2017 年 Google I/O,Google 发布了 Android Architecture Components,这是 Jetpack 的前身:
| 组件 | 解决什么问题 |
|---|---|
| Lifecycle | 生命周期状态观察,替代手动回调 |
| ViewModel | 配置变更期间保留数据,替代 Loader |
| LiveData | 生命周期感知的可观察数据容器,替代各种回调 |
| Room | SQLite 的抽象层,替代手写 SQL 和 Cursor 操作 |
同时发布了 Architecture Guide------Google 第一次对 Android 应用架构给出官方推荐(MVVM + Repository 模式)。 这是转折点。Google 不再只是提供 API,开始告诉开发者"应该怎么用"。
正式发布:Jetpack(2018)
2018 年 Google I/O,Jetpack 品牌正式发布。它将四个东西统一到一个品牌下:
- Foundation --- 基础能力与兼容层(AppCompat、AndroidX KTX、Test 等)
- Architecture --- 生命周期与应用架构(Lifecycle、ViewModel、LiveData、Room、Navigation、Paging 等)
- Behavior --- 系统行为与后台任务(Notification、Permission、Sharing 等)
- UI --- 界面开发相关组件(Fragment、Layout、Animation、Auto 等)
这四个模块,每个模块都用于解决不同的问题,其中,架构模块算是最重要的部分了。如下图:
并在同时,Google 宣布了 AndroidX 的迁移:
groovy
// 旧
implementation 'com.android.support:appcompat-v7:28.0.0'
// 新
implementation 'androidx.appcompat:appcompat:1.0.0'
AndroidX 的关键改变:
- 语义化包名:androidx.recyclerview、androidx.viewpager2------不再有 v4/v7 的误导
- 独立版本号:每个库自己发版,不再绑在一起
- 语义化版本(SemVer):major.minor.patch,含义清晰
快速扩张期(2018-2020)
Jetpack 以极快的速度推出新组件:
| 年份 | 新组件 |
|---|---|
| 2018 | Navigation、Paging、WorkManager、DataBinding、Slices |
| 2019 | CameraX、BiometricPrompt、SavedState、ViewPager2、Compose(alpha) |
| 2020 | Hilt(Dagger 的 Jetpack 封装)、Startup、Window Manager |
每个新组件都遵循统一的设计原则:
- 生命周期感知(基于 Lifecycle)
- Kotlin 优先(KTX 扩展)
- 与其他 Jetpack 组件协作(如 Room 支持 LiveData/Flow,Navigation 支持 ViewModel)
范式转换:Compose(2019-2021)
2019 年 Google I/O,Compose 首次公开。2021 年 7 月,Compose 1.0 正式发布。
Compose 不是 Jetpack 的一个普通组件------它是整个 Android UI 开发范式的转换:
- 命令式 UI(View 系统)→ 声明式 UI(Compose)
- Activity/Fragment 生命周期回调 → 状态驱动的组合与重组
- XML 布局 → Kotlin 代码描述 UI
从 Jetpack 的角度看,Compose 是 Lifecycle、ViewModel、LiveData 这些抽象层的最终归宿 ------ 不再需要"在旧体系上建抽象",而是直接用新范式让问题降级。
现状:MAD 体系(2021-至今)
从 2021 年起,Google 提出了 MAD 的概念,也就是 Modern Android Development, 其本质就是将 Android 开发的方方面面统一起来。它包括了以下的内容:
- Kotlin --- 编程语言
- Jetpack --- 库和工具
- Compose --- 声明式UI
- 工具链 --- Android Studio, Gradle, AGP, Build Analyzer 等
Android 开发最大的问题:生命周期
从 Android 应用开发看来,处理好 APP 的生命周期一直贯穿着应用开发的方方面面,处理稍有不慎就会造成崩溃或是内存泄漏。可以说 Android 的生命周期设计是灾难性的,从 API 1 开始,所有 Android 开发者都不得不与各种各样的生命周期斗智斗勇。而对于这个问题,Google 完全意识不到,甚至在后续为了解决 UI 复用还推出了生命周期更加复杂的 Fragment,不得不说是愚蠢至极。虽然在 Compose 时代,这个 Fragment 已经很少使用,但发布了的东西,只能继续恶心每个 Android 开发者。
然而随着 Android 的发展,生命周期带来的问题愈演愈烈,加之 Google 也需要对 Android 开发架构进行标准化,因此才推出了 Jetpack。而 Jetpack 中最重要的架构组件就是 Lifecycle,这是一个用于处理生命周期的组件,后续的 ViewModel、LiveData 等等,都是建立在 Lifecycle 之上的。Jetpack 的很多核心组件,本质上都是在为 Android 早期设计中缺失的基础设施补课,尤其是生命周期管理问题,甚至可以说,整个 Jetpack 都是为了处理生命周期这个早期的设计问题而做的 workaround。
因此可以说,Android 的生命周期设计是一坨屎,而后续的 Jetpack 也都是在屎上雕花而已。就像苹果的灵动岛一样,设计得再好看,也无法掩饰那难看的额头。如果没有那一坨屎一样的生命周期的话,或者说 Google 在当时能够认真设计一下,那 Android 开发肯定会明朗很多。
Jetpack 带来的问题:开发的碎片化
前面说到的都是 Jetpack 的好处,但事物都是具有两面性,一个东西有好处那它就有弊端。前面说的是好处:统一 Android 架构,解决生命周期难题、声明式UI 等等,那它的坏处是啥呢?简单来说就是一点:将 Android 应用的碎片化带到了 Android 开发中。
使用 Jetpack 之后,你会明显感觉到,项目里的依赖变多了,而且自己基本都不知道调用的方法是来自于哪个依赖的,单单是一个最基础的 lifecycle-runtime,就会间接依赖7、8个库。同一个对象,你调用的一个方法来自于这个库,而通过扩展方法,下一个调用又可能来自不同的库。而 Android 开发者,早已经对此现象放弃了治疗,特别是在使用了 toml 之后,基本都是最大化的引入依赖库。
另一方面,Kotlin 带来的新特性,使得代码的阅读变得越来越困难。之前 Java 以类为基本单位,而 Kotlin 以函数为基本单位,颗粒度变细,组合变得灵活,而这种灵活看似提高了 Android 开发的效率,但在阅读代码上的难度则大大增加,基本上是得不偿失。而 Kotlin 带来的各种新特性,例如 DSL、顶层方法、扩展属性、协程与 Flow 等,进一步提高的 Android 项目的维护成本。
Jetpack 之前的 API 虽然原始,但是逻辑直观,调试方便,容易定位问题,而 Jetpack 之后,你看到的除了魔法,就是魔法,甚至拿到崩溃堆栈,也难以找到是哪一行代码出了问题。
Jetpack 的缺点完全不止这些,但现在就说到这里。总结一下,就是 Jetpack 并不仅仅是一套库。它更是 Google 对 Android 十多年历史问题的一次系统性重构:
- AndroidX 解决依赖体系混乱
- Lifecycle/ViewModel 解决生命周期问题
- Navigation 统一页面流转
- Room 统一数据库访问
- Compose 则尝试彻底重构 UI 开发模式
从 Jetpack 开始,Android 开发就步入了由 Google 官方主导的应用开发架构的阶段,后续的开发者,要考虑的架构方面的问题就少很多了。所以大家,拥抱 Jetpack 吧!
