</>FUNNYGUYZ

MVC、MVP、MVVM 与 MVI

#MVC#MVP#MVVM#MVI
← 学习资料优先级:扩展

核心原理讲解

从 MVC 到 MVP 的演进

  • MVC(Model-View-Controller)
    • 职责分工:XML 充当 View,Model 负责数据,Activity 充当 Controller。
    • 核心痛点:在 Android 中,View(XML)太弱了,Activity 既要处理用户点击事件(Controller 职责),又要处理 UI 渲染和动画(View 职责)。导致 Activity 变得极其臃肿(动辄上千行代码)。而且 View 和 Model 之间存在双向耦合,无法进行单元测试。
  • MVP(Model-View-Presenter)
    • 职责分工:完全隔离了 View 和 Model。View(Activity/Fragment)和 Presenter 之间定义了一层厚厚的“契约接口”(Contract)。View 发生操作调 Presenter 接口,Presenter 处理完调 View 接口。
    • 核心痛点:Presenter 需要持有 View 的强引用,在异步回调返回前如果页面关闭了,极易导致 Activity 泄漏。另外,每个简单的交互都要定义繁琐的接口方法,导致代码量暴增,契约类异常臃肿。

图片 05-1:MVC、MVP 和 MVVM 架构中 View-Model-Controller 依赖与数据流向对比

从 MVP 到 MVVM / MVI 的飞跃

  • MVVM(Model-View-ViewModel)

    • 核心改变:用数据双向绑定单向观察(LiveData/Flow) 替代了 MVP 的接口回调。ViewModel 内部不持有任何 View 的引用,只向外暴露响应式数据。View 主动绑定或观察数据变化。由于 ViewModel 中没有 UI 依赖,可以直接运行在本地 JVM 上跑单元测试。
  • MVI 强化(单向数据流与单一可信数据源)

    • 在传统的 MVVM 中,UI 状态可能分散在多个不同的数据流中(比如 loading、error 独立变化),在复杂场景下容易出现状态“打架”的竞态问题。
    • MVI(Model-View-Intent)倡导单向数据流。将界面所有的显示状态聚合为一个统一、不可变的 UiState(通过 Kotlin sealed class 表达)。UI 只能通过发送 Intent 改变 State,并接收完整的新 State 进行刷新,确保了 UI 状态的绝对一致。

图片 05-2:MVI 模式单向数据流 (Unidirectional Data Flow) 闭环与不可变状态 copy 机制


工程注意事项

  • [!IMPORTANT] MVI 与 Compose 的契合点:MVI 的唯一不可变 UiState 与 Compose 的声明式 UI 天然匹配,因为声明式 UI 的核心关系可以表达为 UI=f(State)UI = f(State)。迁移视图层时,状态与数据流设计通常可以继续复用。