Molecule 架构
源:Molecule
Molecule 是 Cash App 开源的一个库,它有一个激进的理念:使用 Compose 运行时来驱动 Presenter (ViewModel) 层,而不仅仅是 UI 层。
1. 核心理念
通常,我们在 ViewModel 中使用 Flow / StateFlow 来组合数据流。这往往涉及到复杂的 combine, flatMapLatest, distinctUntilChanged 链式调用。
Molecule 认为:既然 Compose 的重组机制(Recomposition)如此擅长处理“状态 -> 结果”的转换,为什么不直接用它来生成 StateFlow 呢?
2. 传统写法 vs Molecule
传统 ViewModel (Flow):
kotlin
val uiState: StateFlow<UiState> = combine(
repo.userStream,
repo.balanceStream,
isLoadingStream
) { user, balance, loading ->
if (loading) UiState.Loading
else UiState.Content(user, balance)
}.stateIn(viewModelScope, SharingStarted.Lazily, UiState.Loading)Molecule 写法 (Composable):
kotlin
@Composable
fun Presenter(
userFlow: Flow<User>,
balanceFlow: Flow<Money>
): UiState {
// 像写 UI 一样写逻辑!
val user by userFlow.collectAsState(initial = null)
val balance by balanceFlow.collectAsState(initial = Money.ZERO)
return if (user == null) {
UiState.Loading
} else {
UiState.Content(user!!, balance)
}
}3. 启动 Molecule
Molecule 提供了一个 launchMolecule 函数,它启动一个协程,在其中运行 Compose Runtime(但不涉及任何 UI 绘制),并将 Composable 的返回值输出为 StateFlow。
kotlin
class MyViewModel : ViewModel() {
val uiState: StateFlow<UiState> = viewModelScope.launchMolecule(mode = RecompositionMode.ContextClock) {
// 这里运行的是 Presenter 逻辑
Presenter(repo.userStream, repo.balanceStream)
}
}4. 优势
- 可读性: 用命令式的代码(if/else, when)写响应式逻辑。
- 副作用管理: 可以直接使用
LaunchedEffect来处理一次性事件(如显示 Toast),而不需要像传统 MVI 那样引入复杂的 Event Channel。 - 测试: 可以像测试 Composable 一样测试 Presenter,甚至可以使用
app.cash.molecule:molecule-test库进行同步测试。