经常能在网上看到开发者争吵对于Android开发,究竟什么样的架构才是最好的。MVC 早已过时,MVP 在现代compose框架下很别扭,所以争论的焦点往往是 MVVM VS MVI。
明确概念区分是有必要的,但我觉得实在是没必要把它当成非黑即白的大事。看过许多开源项目,在 Android + Compose 语境里,所谓 MVVM 和 MVI,实际落地后确实只差一层皮:
现在大家对于状态管理的普遍写法是:
ViewModel持有StateFlow- Compose
collect - UI 调
viewModel.xxx()
这时如果有人嘴上说自己是 MVI,但代码只是:
- 多定义了个
Intent - 多定义了个
Effect onClick改成sendEvent(intent)- 内部拿
when识别接着走不同逻辑
那在我看来,这只是MVVM 套了 MVI 命名风格,不是什么本质区别,这样的MVI实际上根本不足以称之为MVI。MVI 与 MVVM 的真正区别,不在于有没有 Intent / Effect 类型,而在于是否真的在代码中采用了两种不同的状态管理哲学。对于MVI来说:
- 是否有 reducer 思维?
- 是否有严格的单向状态演化约束?
- 是否真正分离了状态和副作用?
在 MVVM 中,ViewModel 是页面逻辑中心,对外暴露状态,并直接提供若干命令式方法给 UI 调用,状态更新逻辑也散落在各方式中,相对自由奔放。例如:
1 | fun onRefresh() { ... } |
这使得业务代码写起来很灵活,直接新增方法就好了,逻辑都写方法里,状态有变化直接在这里update就好了,UI按需调用。代价则是基本没有对状态的任何范式约束。
而在 MVI 中,所有输入先被建模成 Intent;所有页面可见信息收敛成单一 State;状态变化应只通过 reducer 统一规则演化,并且明确隔离副作用,派生出Effect。也就是说,MVI 的重点不是“多定义几个 sealed class”,而是:
- 状态转移是否被统一建模
- 所有用户动作和系统动作是否都走统一入口
- 副作用是否被明确区分,不混进 state
所以说,很多人把区别理解成:MVVM就是UI调用 onClick(),MVI就是UI调用 sendEvent(Intent.Click),这太浅了,也根本不是核心。如果还纠结于类似方法名怎么起、sealed class 要不要写、 一次性事件叫 effect 还是 event 这类价值不高的争论上,实属可惜。真正的区别更接近于:MVVM把ViewModel用来当页面管理者,功能自己设计;而MVI则是把ViewModel当成一个出入口,统一输入输出,内部维护一个状态机,所有输入都驱动状态机的转移,输出新状态。
也因此在我看来,虽然这两种架构经常被放在一起对比,但实际上他们所反映的思路并非同一维度:
- MVVM 是一种更强调对架构的严格分层与View/Model解耦
- MVI 则是在此基础之上,强调状态流转的建模思路
严格讲,很多 Android 项目其实就是MVVM 外壳 + MVI 风格状态管理:
- MVVM解决架构分层:View层对应Composable,ViewModel层就是ViewModel,Model层对应依赖的Repository及其下的数据源;
- MVI解决页面状态流转与事件消费:用 Intent / State / Effect / Reducer 的方式组织。
所以在我看来它们并不完全互斥,很多成熟写法其实就是架构层面是 MVVM 而状态管理层面借鉴 MVI。过度区分是没有必要的,不应为了比较而比较,谁优谁劣更是没有定数。