项目刚起步时,所有代码塞进一个
app模块完全没问题。但随着功能越来越多,你会发现:改一行代码要全量编译几分钟、不同团队改同一个模块频繁冲突、想复用某块功能却发现它和一堆东西耦合在一起拆不出来。这时就该上多模块化(Modularization):把一个巨大的
app拆成多个职责清晰、可独立编译、可复用的 module,就像把一栋大楼分成若干独立单元。本文讲清为什么拆、怎么拆、模块间如何通信。
一、为什么要多模块化
| 收益 | 说明 |
|---|---|
| 编译更快 | 只重新编译改动的模块(增量编译 + 并行) |
| 职责清晰 | 每个模块边界明确,强制解耦 |
| 可复用 | 通用模块可被多个 App / feature 复用 |
| 团队协作 | 不同团队负责不同模块,减少冲突 |
| 按需交付 | 配合 Dynamic Feature 实现功能动态下发 |
经验信号:当全量编译超过几分钟、或多人频繁在同一文件冲突时,就该考虑拆模块了。
二、常见的分层模块策略
一种被广泛采用的分层(参考官方 Now in Android 架构):
:app 应用入口,组装各 feature ├── :feature:home 功能模块(首页) ├── :feature:profile 功能模块(个人中心) ├── :core:ui 通用 UI 组件、主题 ├── :core:data Repository、数据源整合 ├── :core:network 网络层(Retrofit/OkHttp) ├── :core:database 数据库层(Room) ├── :core:model 纯数据模型(无依赖) └── :core:common 工具类、扩展函数依赖方向规则(关键):
app ──> feature ──> core永远是上层依赖下层,下层绝不反向依赖上层;feature 模块之间也不互相依赖。
三、模块类型
| 类型 | Gradle 插件 | 用途 |
|---|---|---|
| 应用模块 | com.android.application | 最终 App,只能有一个入口 app |
| 库模块 | com.android.library | feature/core 模块,产出 aar |
| 纯 Kotlin 模块 | org.jetbrains.kotlin.jvm | 无 Android 依赖的逻辑/模型层 |
| Dynamic Feature | com.android.dynamic-feature | 按需下载的功能模块 |
:core:model、:core:common这类不依赖 Android API 的模块尽量做成纯 Kotlin 模块,编译更快、也能被测试直接用。
四、模块间通信与解耦
模块拆开后,怎么让:feature:home用到:feature:profile的能力,又不直接依赖它?
- 接口下沉:把公共接口放到下层
:core模块,feature 依赖接口而非实现。 - 依赖注入:用 Hilt 在 app 层组装实现,feature 只声明需要什么。
- 导航解耦:用 Navigation 的 deep link 跨模块跳转,避免直接引用对方 Activity/Fragment 类。
五、用 Version Catalog 统一依赖
多模块下最怕"各模块依赖版本不一致"。用gradle/libs.versions.toml(Version Catalog)集中管理:
[versions] retrofit = "2.11.0" [libraries] retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }// 任意模块dependencies{implementation(libs.retrofit)}再配合convention plugins(约定插件)把各模块重复的构建配置抽出来,避免每个build.gradle复制粘贴。
六、apivsimplementation
| 关键字 | 依赖是否传递给上游 |
|---|---|
implementation | 不传递(默认首选,编译更快) |
api | 传递(上游也能用到这个依赖) |
默认用
implementation。滥用api会让依赖"穿透"多层模块,破坏封装,还会拖慢编译——改一个底层依赖导致一大片模块重编。