Skip to content

MVI 是 UI 架构演进的"终点站"之一,Jetpack Compose、Redux 都基于它的思想。它解决的是《MVVM 模式》遗留的"状态分散、数据流难追踪"问题。这篇把 MVI 的核心——单向数据流、不可变状态——讲清楚。

一、解决什么问题:MVVM 的状态分散

MVVM 的双向绑定好用,但有个隐患:状态散落各处,数据流不透明

  • 一个界面可能有多个 LiveData、多个双向绑定
  • 状态怎么变的、谁改的、什么时候改的,追踪困难
  • 复杂界面下,多个状态互相影响,出现"改 A 意外影响了 B"的 bug,排查半天

MVI 的思路是反过来的:状态只有一个、数据只能单向流——把"状态"集中成一个不可变对象,任何变化都走同一条路,有迹可循。

二、MVI 三部分

部分职责特点
Model界面状态(State)不可变(immutable)
View渲染状态 + 发送 Intent只渲染,不持有业务状态
Intent用户意图(事件)用户干了啥,就发啥

关键区别:MVI 里的 Model 不是"数据+业务",而是"界面状态"(当前加载中?列表数据是啥?)。View 渲染它,用户操作发 Intent,Intent 处理后产生新的 State,View 再渲染。

三、单向数据流(核心)

MVI 的核心是数据只朝一个方向流,没有回头路

View 发送 Intent → 处理(Reducer)→ 产生新 State → View 渲染新 State
      └──────────────── 单向,无环 ──────────────────┘

用 Compose 看最直观:

kotlin
// ① State:不可变状态(data class,每次产生新的)
data class UiState(
    val loading: Boolean = false,
    val users: List<User> = emptyList(),
    val error: String? = null
)

// ② Intent:用户意图(sealed class,枚举所有用户操作)
sealed class UserIntent {
    data class LoadUsers(val deptId: Int) : UserIntent()
    object Refresh : UserIntent()
}

// ③ 处理:Intent → 新 State(纯函数,输入确定输出就确定)
fun reduce(state: UiState, intent: UserIntent): UiState = when (intent) {
    is UserIntent.LoadUsers -> state.copy(loading = true)
    UserIntent.Refresh -> state.copy(loading = true)
}

// ④ View 渲染 State,发 Intent
// 用户点"刷新" → 发 Refresh Intent → reduce 产生 loading=true 的新 State → View 显示加载中

四个关键点:

  1. 单向Intent → State → View,永远一个方向,不会像双向绑定那样来回
  2. 不可变 Statestate.copy(loading = true) 产生新对象,不改旧对象——旧状态永远可追溯
  3. 状态集中:一个界面的状态就是一个 UiState,不再散落成多个 LiveData
  4. 可追溯:任何时刻的状态,都是"初始 State + 一串 Intent"一步步 reduce 出来的,debug 时能完整回放

四、MVI vs MVVM

维度MVVMMVI
数据流双向绑定(来回)单向数据流(一个方向)
状态分散(多个 LiveData)集中(单一不可变 State)
状态变化难追踪可追溯(Intent 回放)
典型Vue、DataBindingCompose、Redux、Flutter

一句话:MVVM 图省事(双向自动同步),MVI 图可控(单向可追溯)

MVI 单向数据流:View 发 Intent → 处理产生新 State → View 渲染,无环可追溯

五、落地

  • Jetpack ComposeMutableStateFlow<UiState> + sealed class Intent,状态提升(State Hoisting)
  • ReduxStore → Action → Reducer → State,MVI 就是 Redux 思想在 UI 的落地
  • FlutterBloc 模式(Event → Bloc → State)

小结

  • MVI 解决 MVVM"状态分散、难追踪"的问题,核心是单向数据流 + 不可变状态
  • 三部分:State(不可变状态)+ View(渲染 + 发 Intent)+ Intent(用户意图)
  • 数据流:View 发 Intent → reduce 产生新 State → View 渲染,单向无环、可回放
  • 落地:Compose、Redux、Flutter Bloc

MVI 是目前 UI 架构里"可维护性"最强的一档,代价是样板代码比 MVVM 多——简单界面 MVVM 够用,复杂状态多的界面用 MVI 更省心。想了解这三个模式的源头,回头看《MVC 模式》。