模块化架构
问题
Android 模块化架构如何设计?模块之间如何通信?
答案
模块化拆分策略
模块类型说明
| 模块类型 | 说明 | 示例 |
|---|---|---|
| app | 壳模块,组装 Feature | app |
| feature-* | 业务功能模块 | feature-home, feature-login |
| core-* | 基础能力模块 | core-network, core-ui |
| common | 通用工具 | 工具类、扩展函数 |
模块间通信
Feature 模块之间不能直接依赖,通过以下方式通信:
方式一:Navigation(推荐)
// feature-home 跳转到 feature-profile
// 使用 Deep Link,无需直接依赖
navController.navigate("app://profile/user123")
方式二:接口下沉 + DI
// core-common 中定义接口
interface UserService {
suspend fun getCurrentUser(): User
}
// feature-profile 中实现
@Singleton
class UserServiceImpl @Inject constructor(
private val userRepo: UserRepository
) : UserService {
override suspend fun getCurrentUser() = userRepo.getUser()
}
// feature-home 中通过 DI 注入接口
@HiltViewModel
class HomeViewModel @Inject constructor(
private val userService: UserService
) : ViewModel()
Gradle 配置
feature-home/build.gradle.kts
plugins {
id("com.android.library")
id("dagger.hilt.android.plugin")
}
dependencies {
implementation(project(":core-network"))
implementation(project(":core-ui"))
implementation(project(":core-common"))
// 不依赖其他 feature 模块
}
Convention Plugin
使用 Gradle Convention Plugin 统一模块配置,避免每个模块重复配置 compileSdk、minSdk 等参数:
build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt
class AndroidLibraryConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.android.library")
pluginManager.apply("org.jetbrains.kotlin.android")
extensions.configure<LibraryExtension> {
compileSdk = 34
defaultConfig.minSdk = 24
}
}
}
}
常见面试问题
Q1: 模块化有什么好处?
答案:
- 编译速度:只重新编译修改的模块,增量编译更快
- 代码隔离:Feature 模块互不依赖,避免耦合
- 团队协作:不同团队负责不同模块,减少合并冲突
- 动态化:可配合 Dynamic Feature 实现按需下载
Q2: 如何避免模块间循环依赖?
答案:
- 严格遵循依赖方向:
app → feature → core,不允许反向依赖 - Feature 模块之间不直接依赖,通过接口下沉到 core 层
- 使用 Gradle 的
api/implementation控制传递依赖范围 - CI 中添加架构检查(如 module-graph)
Q3: 模块化和组件化有什么区别?
答案:
- 模块化:按功能拆分 Gradle Module,编译隔离,关注代码组织
- 组件化:模块化的进阶,每个组件可独立运行和调试(通过切换
com.android.application/com.android.library),关注独立运行能力