Skip to content

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. 优势

  1. 可读性: 用命令式的代码(if/else, when)写响应式逻辑。
  2. 副作用管理: 可以直接使用 LaunchedEffect 来处理一次性事件(如显示 Toast),而不需要像传统 MVI 那样引入复杂的 Event Channel。
  3. 测试: 可以像测试 Composable 一样测试 Presenter,甚至可以使用 app.cash.molecule:molecule-test 库进行同步测试。