引言:从'能跑就行'到'优雅可维'——架构即工程文明
站在 2025 年回望,Android 开发已走过近二十年。从早期'Activity 即一切'的野蛮生长,到如今以 为核心的现代开发范式,应用架构的演进不仅是技术的升级,更是工程思维的成熟。
Android 架构从 MVC 到 MVVM 再到 MVI 的演进过程。MVC 在 Android 中因 Activity 兼任 Controller 导致耦合高、测试难。MVP 通过引入 Presenter 实现解耦,但增加样板代码和生命周期管理负担。MVVM 利用 LiveData/StateFlow 实现数据驱动和自动同步,成为主流。现代架构结合分层设计、协程与 Flow,强调状态管理与可测试性。

站在 2025 年回望,Android 开发已走过近二十年。从早期'Activity 即一切'的野蛮生长,到如今以 为核心的现代开发范式,应用架构的演进不仅是技术的升级,更是工程思维的成熟。
在这条演进之路上,MVC、MVP、MVVM 三大模式如同三座里程碑,分别代表了 Android 社区在不同阶段对关注点分离(Separation of Concerns)、可测试性(Testability) 和状态管理(State Management) 的探索与突破。今天,我们不仅回顾它们'是什么',更要理解它们'为何而来'、'因何而去',以及它们如何共同塑造了今日 Android 开发的底层逻辑。
在架构意识尚未觉醒的年代,一个典型的 MainActivity 往往集万千职责于一身:
findViewById 操作 UI 控件;onCreate() 中处理业务逻辑分支;onActivityResult() 中解析 Intent 数据;AsyncTask 处理异步任务……这种'上帝类'模式看似高效,实则埋下巨大隐患:
| 问题维度 | 具体表现 |
|---|---|
| 高耦合 | UI、网络、DB、业务逻辑全部交织,修改一处可能引发连锁崩溃 |
| 不可测试 | 业务逻辑强依赖 Context、Activity 等 Android SDK 类型,无法脱离设备运行单元测试 |
| 状态脆弱 | 屏幕旋转导致 Activity 重建,未妥善保存的数据(如网络加载中的状态)瞬间丢失 |
| 维护地狱 | 单文件超 2000 行代码,新人接手需数周才能理清逻辑 |
正是这种'开发快、维护慢、测试难'的恶性循环,催生了对架构模式的迫切需求。而第一个被引入的,便是软件工程的经典范式——MVC。
MVC 的核心在于三者职责分离:
但在 Android 中,没有独立的 Controller。Activity / Fragment 被迫同时承担 View(UI 渲染) 和 Controller(事件处理) 双重角色:
+------------------+
| Model | ←→ (数据)
+------------------+
↑
| (调用/回调)
+-------------------------------+
| Activity/Fragment (V + C) |
| - setContentView() |
| - findViewById() |
| - onClick() { |
| model.fetchData(); |
| updateUI(); |
| } |
+-------------------------------+
↑
| (布局引用)
+------------------+
| XML Layout | ← (View)
+------------------+
贡献:
局限:
Activity 既是 View 又是 Controller,解耦不彻底。Activity 中,无法进行纯 JVM 单元测试。2025 年回看:MVC 更像是一次'思想启蒙',而非实用方案。它暴露了 Android 框架设计与经典 MVC 的天然冲突,为 MVP 的登场埋下伏笔。
MVP 通过引入 Presenter 彻底切断 View 与 Model 的直接联系,实现'被动视图'理念。
Activity / Fragment 实现的接口,仅暴露 UI 操作方法(如 showLoading()、updateList())。View(Activity) -> Presenter -> Model(Repo)
onUserClick() fetchData()
return data
showData(data)
onSaveInstanceState / onRestoreInstanceState 保存 Presenter 状态。样板代码爆炸:
interface MainContract {
interface View {
fun showUsers(users: List<User>)
fun showError(msg: String)
}
interface Presenter {
fun loadUsers()
}
}
每个页面需定义 Contract 接口,Presenter 与 View 方法一一对应。
2025 年反思:MVP 是'为了解耦而解耦'的典型。它解决了 MVC 的痛点,却引入了新的复杂性。其兴盛(约 2016–2019)恰逢 Android 单元测试文化兴起,但最终被更优雅的 MVVM 取代。
MVVM 的崛起,离不开 Google Jetpack 的强力推动。它不再依赖'接口回调',而是通过 可观察数据 + 生命周期感知 实现自动同步。
androidx.lifecycle.ViewModel,持有 LiveData / StateFlow 封装的 UI 状态。Activity / Fragment 通过 observe() 监听状态变化,自动更新 UI。class MainViewModel : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> = _users
fun loadUsers() {
viewModelScope.launch {
_users.value = repository.getUsers()
}
}
}
// Activity 中
viewModel.users.observe(this) { users ->
adapter.submitList(users)
}
setText() / notifyDataSetChanged()。LiveData 仅在 LifecycleOwner(如 Activity)处于 STARTED/RESUMED 时通知,避免空指针与内存泄漏。ViewModel 由 ViewModelProvider 管理,在屏幕旋转等场景下自动保留实例。ViewModel 不依赖 Android Context,可轻松单元测试。2025 年现状:MVVM 已成为 Android 官方推荐架构的核心,尤其与 Jetpack Compose 结合后,形成'状态驱动 UI'的终极形态。
MVVM 并非终点。随着应用复杂度提升与声明式 UI 的普及,新一代架构思想正在融合演进:
MVI 将用户操作抽象为 Intent,状态变更通过 Reducer 生成新 State,形成严格单向流:
sealed class MainIntent {
object LoadUsers : MainIntent()
}
data class MainState(
val isLoading: Boolean = false,
val users: List<User> = emptyList(),
val error: String? = null
)
class MainViewModel : ViewModel() {
private val _state = MutableStateFlow(MainState())
val state: StateFlow<MainState> = _state.asStateFlow()
fun processIntent(intent: MainIntent) {
when (intent) {
is MainIntent.LoadUsers -> loadUsers()
}
}
private fun loadUsers() {
// 更新 state via _state.update { ... }
}
}
优势:状态可预测、可回溯、易于时间旅行调试(Time Travel Debugging)。
契合 Compose:Compose 的 @Composable 函数天然适配'State → UI'映射。
Google 在 Guide to app architecture 中明确推荐三层架构:
┌──────────────┐
│ UI Layer │ ← ViewModel + Compose/ViewBinding
├──────────────┤
│ Domain Layer │ ← UseCase (封装复杂业务)
├──────────────┤
│ Data Layer │ ← Repository + DataSource (Retrofit, Room)
└──────────────┘
LiveData 逐渐被 StateFlow / SharedFlow 取代,因其支持冷流、背压、组合操作符。| 维度 | MVC | MVP | MVVM | MVI(2025) |
|---|---|---|---|---|
| 状态持有者 | Activity | Presenter | ViewModel | StateFlow |
| UI 更新方式 | 手动调用 | 回调接口 | 观察数据 | 响应状态 |
| 生命周期管理 | 手动 | 手动(易错) | 自动 | 自动 |
| 可测试性 | 差 | 好 | 极好 | 极好 |
| 核心哲学 | 分离职责 | 彻底解耦 | 数据驱动 | 单向数据流 |
架构没有银弹,只有权衡(Trade-offs)。 MVC 教会我们'分层',MVP 教会我们'解耦',MVVM 教会我们'响应式',MVI 教会我们'状态即真理'。
站在 2025 年,我们不再争论'用 MVP 还是 MVVM',而是思考:
而这一切的起点,正是当年那个试图从'上帝 Activity'中挣脱出来的你。
结语: 理解 MVC、MVP、MVVM,不是为了怀旧,而是为了看清—— 所有架构的本质,都是对'复杂性'的驯服。 愿你在未来的代码中,始终握紧这把名为'关注点分离'的罗盘。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online