Jetpack Compose 已成为 Android 官方推荐的 UI 工具包,但声明式范式下的状态管理和架构设计与传统 View 系统截然不同。本文基于实际项目经验,分享一套经过验证的 Compose 架构方案。
单向数据流(UDF)
Compose 的核心原则是 UI 是状态的函数:UI = f(state)。数据应单向流动:
事件向上传递(User Action → ViewModel),状态向下流动(ViewModel → Composable)
@Composable
fun UserScreen(viewModel: UserViewModel = hiltViewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
UserContent(
state = uiState,
onRefresh = viewModel::refresh,
onUserClick = viewModel::selectUser
)
}
UiState 密封类设计
用密封类(sealed class/interface)表达 UI 的所有可能状态,避免多个 Boolean 标志位:
sealed interface UserUiState {
data object Loading : UserUiState
data class Success(val users: List<User>) : UserUiState
data class Error(val message: String) : UserUiState
}
Composable 中用 when 穷举所有分支,编译器会检查遗漏,杜绝「忘记处理 Loading 状态」的 bug。
状态提升与 Composable 职责
Composable 分为两类:
- 有状态 Composable:管理自身 UI 状态(如 TextField 输入、展开/折叠),用
remember保存 - 无状态 Composable:纯展示,所有数据通过参数传入,便于预览和测试
经验法则:默认写无状态 Composable,仅在状态不需要跨组件共享时才在内部持有。
导航:Navigation Compose
Navigation Compose 2.x 支持类型安全路由(Kotlin Serialization):
@Serializable data object HomeRoute
@Serializable data class DetailRoute(val id: String)
NavHost(navController, startDestination = HomeRoute) {
composable<HomeRoute> { HomeScreen(onNavigate = { id ->
navController.navigate(DetailRoute(id))
}) }
composable<DetailRoute> { backStackEntry ->
val route = backStackEntry.toRoute<DetailRoute>()
DetailScreen(id = route.id)
}
}
模块化策略
中大型项目推荐按功能模块拆分 Gradle module:
:core:ui— 主题、通用 Composable、扩展函数:core:data— Repository、数据源、网络层:feature:home— 首页的 ViewModel + Screen + Navigation:feature:detail— 详情页独立模块:app— 组装入口、Hilt 依赖注入图
性能注意事项
- 使用
derivedStateOf避免不必要的重组 - 列表用
LazyColumn+key参数,稳定 item 身份 - 避免在 Composable 内创建重量级对象(Regex、DateFormat),用
remember缓存 - 用 Layout Inspector 的 Recomposition Count 定位过度重组
小结
Compose 架构的基石是单向数据流 + 密封类 UiState + 无状态 Composable。配合 Hilt 依赖注入和模块化拆分,可以构建出可测试、可维护的现代 Android 应用。