为什么需要架构
架构让人改得动:可测试、可复用、可并行开发,需求变更时改动被关进最小边界。没有银弹,按需取舍。
Google 官方推荐 UI 层 → 领域层 → 数据层 的分层,UI 只渲染状态、数据层屏蔽来源(网络/本地)。
MVVM
Model-View-ViewModel:UI 观察 ViewModel 暴露的 StateFlow,事件回传给 VM,VM 不持有任何 View 引用,便于测试。
class LoginViewModel(private val repo: AuthRepository) : ViewModel() {
private val _state = MutableStateFlow(LoginState())
val state = _state.asStateFlow()
fun login(u: String, p: String) = viewModelScope.launch {
_state.value = _state.value.copy(loading = true)
// 调用 repo,更新 state
}
}ViewModel 生命周期
ViewModel 存活于配置变更(旋转),屏幕销毁才清理。是保存 UI 状态、持有协程的最佳容器。
复杂状态用 SavedStateHandle 跨进程重建持久化,避免被杀后台后状态丢失。
Repository 模式
Repository 统一数据来源(远程+本地),对外暴露领域模型,UI/VM 不关心数据来自网络还是数据库缓存。
class UserRepository(
private val api: UserApi,
private val dao: UserDao
) {
fun users(): Flow<List<User>> =
dao.observe().onEmpty { emit(api.fetch().also { dao.insert(it) }) }
}依赖注入与 Hilt
Hilt(基于 Dagger)在编译期生成注入代码,用 @Inject 构造函数与 @Module 提供依赖,避免手动 new 与全局单例。
@HiltViewModel
class HomeViewModel @Inject constructor(
private val repo: UserRepository
) : ViewModel() { /* ... */ }
@Module @InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides fun provideApi(): UserApi = Retrofit.Builder()...build().create()
}单向数据流
UI 发出事件 → VM 处理 → 产生新状态 → UI 渲染。状态只读暴露,事件是唯一入口,逻辑可预测可测试。
| 方向 | 载体 |
|---|---|
| UI → VM(意图) | 方法调用 / Channel |
| VM → UI(状态) | StateFlow / Compose 状态 |
模块拆分
用 Gradle 模块按特性/层拆分(:feature:home、:core:network),控制编译耦合、提升并行编译与复用。
上层依赖下层,下层不反向引用上层,否则循环依赖且无法单独测试。接口是跨层解耦的关键。
常见陷阱
不要持有 Activity Context(会泄漏)。需要 Context 时用 AndroidViewModel 的 Application Context,或注入轻量工具类。
手动单例难替换、难测试。Hilt 编译期生成、可轻松注入测试替身,且避免全局可变状态。