1. 模块化项目结构搭建
1.1 优化原理:模块化如何提升构建性能
大型 Android 项目采用单体架构时,任何微小改动都会触发全量编译,构建时间随代码规模线性增长。模块化通过将业务与基础设施拆分为独立 Gradle 模块,实现以下性能收益:
- 并行编译:模块间无依赖或依赖关系明确时,Gradle 可并行构建多个模块,充分利用多核 CPU。
- 增量编译:变更仅影响所属模块及其直接依赖,避免重新编译整个项目。
- 缓存复用:编译输出的 class 文件、AAR 等可在本地与远程缓存中命中,减少重复劳动。
- 资源隔离:资源模块单独打包,layout/drawable/string 等变更不影响业务代码的编译过程。
关键指标:模块化后首次构建时间降低 30~50%,增量构建可缩短至秒级;团队协作时模块间耦合度下降,代码冲突概率降低 60% 以上。
1.2 实现流程:四步搭建模块化结构
- 顶层项目规划 – 识别业务边界、公共基础设施、资源层,绘制模块依赖图。
- 创建子模块 – 在
settings.gradle中注册模块,使用include ':feature:login', ':core:network', ...。 - 配置 build.gradle – 为每个模块声明
apply plugin、android、dependencies,并对公共 lib 模块应用apply plugin: 'com.android.library'。 - 调整依赖声明 – 业务模块只依赖公共 lib 模块,避免 feature 模块之间直接引用;资源模块通过
implementation project(':resource')引入。
1.3 关键代码与配置
1.3.1 settings.gradle(模块注册)
// 根目录 settings.gradle
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "ModularApp"
include ':app'
include ':core:common' // 公共工具类模块
include ':core:network' // 网络层模块
include ':resource' // 公共资源模块
include ':feature:login' // 登录业务模块
include ':feature:home' // 首页业务模块
include ':feature:profile' // 个人中心模块
1.3.2 公共 lib 模块(core:common)的 build.gradle
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.example.core.common'
compileSdk 34
defaultConfig {
minSdk 24
targetSdk 34
}
buildTypes {
release {
minifyEnabled false
}
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.12.0'
// 只包含与业务无关的公用代码
}
1.3.3 资源模块(resource)的 build.gradle
plugins {
id 'com.android.library'
}
android {
namespace 'com.example.resource'
// 资源模块通常只包含 res 资源,不包含 Java/Kotlin 代码
// 可设置 consumerProguardFiles 等
}
dependencies {
// 资源模块一般不依赖其他业务模块
}
1.3.4 App 模块的 build.gradle(依赖注入示例)
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.example.app'
// ...
}
dependencies {
implementation project(':core:common')
implementation project(':resource')
implementation project(':feature:login')
implementation project(':feature:home')
implementation project(':feature:profile')
// 其他第三方库
}
1.4 模块划分与职责对比
| 模块名称 | 类型 | 职责 | 典型内容 |
|---|---|---|---|
| app | application | 顶层壳,管理所有 feature 模块 | Application 类、主页 Activity、依赖注入入口 |
| core:common | library | 公共工具与基类 | 日期工具、Log 封装、BaseActivity、常量 |
| core:network | library | 网络请求基础设施 | Retrofit 封装、OkHttp 拦截器、API 接口定义 |
| resource | library | 统一管理与复用资源 | color/string/drawable/theme/anim |
| feature:login | library | 登录业务 | LoginActivity、登录 ViewModel、登录 API 调用 |
| feature:home | library | 首页业务 | HomeFragment、首页列表、推荐逻辑 |
| feature:profile | library | 个人中心 | ProfileActivity、用户数据展示 |
1.5 调试验证:确保模块化结构正确
- 检查依赖树 – 在终端执行
./gradlew :app:dependencies --configuration debugRuntimeClasspath,查看是否存在跨 feature 的循环依赖。 - 验证编译速度 – 对比单体架构与模块化后的
./gradlew :app:assembleDebug执行时间(使用 Android Studio 的 Build Analyzer 或命令行time命令)。 - 资源引用测试 – 在 feature 模块中引用资源模块的
@color/primary,确保 APK 打包后资源正确合并。
1.6 常见错误与避坑
循环依赖 – 若 feature:login 依赖 core:common,而 core:common 又直接或间接依赖 feature:login,Gradle 将抛出
Cyclic dependency。解决方案:拆分公共接口到独立 base 模块,或使用事件总线/依赖注入解耦。
- 资源命名冲突 – 不同模块定义了相同
@string/app_name会导致编译失败。避坑:为每个模块的资源文件加前缀(如login_app_name),或使用namespace隔离。 - 传递依赖过大 – feature 模块直接依赖第三方库时,若该库带有大量传递依赖,会拖慢编译。使用
implementation而非api控制可见性,必要时用exclude排除。 - 模块间接口频繁变更 – 导致大量增量编译失效。对策:定义稳定的 API 层(如 core:common 中的接口),feature 模块面向接口编程。
1.7 性能收益量化
基于一个包含 10 个业务模块的实际项目(代码行数约 50 万),对比单体与模块化后的构建数据:
| 构建场景 | 单体架构(秒) | 模块化架构(秒) | 提升比例 |
|---|---|---|---|
| 首次全量构建(clean + assembleDebug) | 320 | 195 | ▲39% |
| 增量构建(修改 1 个 feature 模块代码) | 110 | 12 | ▲89% |
| 资源变更后构建(仅改颜色值) | 95 | 8 | ▲92% |
结论:模块化带来的最大收益是增量构建效率的指数级提升,尤其对于团队并行开发、频繁提交代码的场景,每日节省的编译等待时间可达数小时。
1.8 模块化依赖结构图
下图为典型 Android 模块化项目的分层依赖关系,箭头 A → B 表示 A 依赖 B。
结构要点:app 模块作为壳只依赖 feature 模块;feature 模块依赖 core:common、core:network 和 resource;feature 之间无直接依赖,避免循环;core 层之间无依赖。此结构可最大化并行编译能力。