目录
[2.1 MVC的基本概念](#2.1 MVC的基本概念)
[2.2 Android中的MVC实现](#2.2 Android中的MVC实现)
[2.3 MVC的优势与问题](#2.3 MVC的优势与问题)
[3.1 MVP的核心思想(解耦的极致追求)](#3.1 MVP的核心思想(解耦的极致追求))
[3.2 MVP的关键特征](#3.2 MVP的关键特征)
[3.3 MVP的实现示例](#3.3 MVP的实现示例)
[3.3.1 UserContract.java](#3.3.1 UserContract.java)
[3.3.2 UserPresenter.java (Presenter层)](#3.3.2 UserPresenter.java (Presenter层))
[3.3.3 UserActivity.java (View层)](#3.3.3 UserActivity.java (View层))
[3.3.4 UserModel.java (Model层)](#3.3.4 UserModel.java (Model层))
[3.4 MVP的优势与挑战](#3.4 MVP的优势与挑战)
[4.1 MVVM的设计理念](#4.1 MVVM的设计理念)
[4.2 MVVM的关键技术](#4.2 MVVM的关键技术)
[4.3 MVVM的实现示例](#4.3 MVVM的实现示例)
[4.3.1 UserViewModel.kt (ViewModel层)](#4.3.1 UserViewModel.kt (ViewModel层))
[4.3.2 UserActivity.kt (View层)](#4.3.2 UserActivity.kt (View层))
[4.3.3 activity_user.xml](#4.3.3 activity_user.xml)
[4.4 MVVM的优势与考量](#4.4 MVVM的优势与考量)
[五、MVI ------ 2025 年的架构新范式](#五、MVI —— 2025 年的架构新范式)
[4.1 MVI核心理念:单向数据流](#4.1 MVI核心理念:单向数据流)
[4.2 MVI核心组件详解](#4.2 MVI核心组件详解)
[4.2.1 Model - 应用状态](#4.2.1 Model - 应用状态)
[4.2.2 View - 状态渲染器](#4.2.2 View - 状态渲染器)
[4.2.3 Intent - 用户意图](#4.2.3 Intent - 用户意图)
[4.2.4 ViewModel - Reducer概念](#4.2.4 ViewModel - Reducer概念)
在Android开发的世界里,架构模式的选择直接影响着应用的可维护性、可测试性和可扩展性。随着Android平台的不断演进,架构模式也从早期的MVC发展到MVP再到如今的MVVM,并涌现出像MVI这样的新思路。本文将深入探讨Android架构模式的演变历程,分析每种模式的特点、优势与局限。
一、为什么要使用架构
在架构意识尚未觉醒的年代,一个典型的 MainActivity 往往集万千职责于一身:
-
通过
findViewById操作 UI 控件; -
直接发起 OkHttp 网络请求;
-
使用 Room 或 SQLiteOpenHelper 操作数据库;
-
在
onCreate()中处理业务逻辑分支; -
在
onActivityResult()中解析 Intent 数据; -
甚至内嵌
AsyncTask处理异步任务......
这种"上帝类"模式看似高效,实则埋下巨大隐患:
| 问题维度 | 具体表现 |
|---|---|
| 高耦合 | UI、网络、DB、业务逻辑全部交织,修改一处可能引发连锁崩溃 |
| 不可测试 | 业务逻辑强依赖 Context、Activity 等 Android SDK 类型,无法脱离设备运行单元测试 |
| 状态脆弱 | 屏幕旋转导致 Activity 重建,未妥善保存的数据(如网络加载中的状态)瞬间丢失 |
| 维护地狱 | 单文件超 2000 行代码,新人接手需数周才能理清逻辑 |
正是这种"开发快、维护慢、测试难"的恶性循环,催生了对架构模式的迫切需求。而第一个被引入的,便是软件工程的经典范式------MVC。
二、传统起点:MVC模式
2.1 MVC的基本概念
MVC(Model-View-Controller)是最早被引入Android开发的架构模式,它将应用程序分为三个核心组件:
Model:负责数据和业务逻辑,与数据库、网络等数据源交互
View :用户界面,负责数据的可视化展示, Acitivity(View)、Fragment(View)视图,在android里xml布局转成View后,加载到了Activity/Fragment里了。
Controller :**协调Model和View之间的交互,**Controller对应着Activity/Fragment,绑定UI,处理各种业务。
2.2 Android中的MVC实现
在传统的Android MVC实现中:
-
Model:数据类、数据库操作类、网络请求类
-
View:XML布局文件
-
Controller:Activity和Fragment
java
// 传统MVC示例
public class UserActivity extends AppCompatActivity {
// Controller部分
private TextView nameTextView; // View部分
private UserModel userModel; // Model部分
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
nameTextView = findViewById(R.id.name_text_view);
userModel = new UserModel();
loadUserData();
}
private void loadUserData() {
User user = userModel.getUser(); // 从Model获取数据
nameTextView.setText(user.getName()); // 更新View
}
}
2.3 MVC的优势与问题
优势:
-
结构简单,容易理解
-
职责分离,有一定程度的模块化
问题:
-
Activity/Fragment负担过重:既承担Controller职责,又处理View逻辑
-
测试困难:业务逻辑与Android组件紧密耦合
-
代码臃肿:随着功能增加,Activity可能变得非常庞大
三、改进之路:MVP模式
3.1 MVP的核心思想(解耦的极致追求)
MVP(Model-View-Presenter)模式针对MVC的问题进行了改进,引入了Presenter层:
Model:与MVC相同,负责数据和业务逻辑
View:界面显示,通过接口定义与Presenter的契约
Presenter:中间人,处理业务逻辑,协调Model和View
3.2 MVP的关键特征
View通过接口抽象:减少对Android框架的依赖
Presenter持有View弱引用:避免内存泄漏
单向数据流:View → Presenter → Model → Presenter → View
3.3 MVP的实现示例
3.3.1 UserContract.java
java
//抽象接口
public interface UserContract {
interface View {
void showUserName(String name);
void showError(String message);
}
interface Presenter {
void loadUser();
void onDestroy();
}
}
✅ 作用:明确定义View和Presenter之间的通信协议
View接口 :定义UI能做什么(显示数据、显示错误)
Presenter接口 :定义业务逻辑能做什么(加载用户、清理资源)
3.3.2 UserPresenter.java (Presenter层)
java
// Presenter实现
public class UserPresenter implements UserContract.Presenter {
private UserContract.View view;
private UserModel model;
public UserPresenter(UserContract.View view) {
this.view = view;
this.model = new UserModel();
}
@Override
public void loadUser() {
model.getUser(new Callback<User>() {
@Override
public void onSuccess(User user) {
if (view != null) {
view.showUserName(user.getName());
}
}
@Override
public void onError(String message) {
if (view != null) {
view.showError(message);
}
}
});
}
@Override
public void onDestroy() {
view = null; // 避免内存泄漏
}
}
✅ 核心职责:
作为 View和Model的中介
处理业务逻辑
从Model获取数据,处理后通知View更新
将两者彻底分开,互不干扰,将职责分离
3.3.3 UserActivity.java (View层)
java
// Activity作为View实现
public class UserActivity extends AppCompatActivity implements UserContract.View {
private UserPresenter presenter;
private TextView nameTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
nameTextView = findViewById(R.id.name_text_view);
presenter = new UserPresenter(this);
presenter.loadUser();
//也可以是点击触发
}
@Override
public void showUserName(String name) {
nameTextView.setText(name);
}
@Override
public void showError(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
presenter.onDestroy();
}
}
✅ 核心职责:
只负责 UI显示和用户交互
实现View接口,成为Presenter的"客户端"
将业务逻辑委托给Presenter处理
3.3.4 UserModel.java (Model层)
java
// 假设的Model类
public class UserModel {
public void getUser(Callback<User> callback) {
// 模拟网络请求或数据库查询
new Handler().postDelayed(() -> {
callback.onSuccess(new User("张三"));
}, 1000);
}
}
✅ 核心职责:
数据获取(网络、数据库、文件等)
数据处理和存储
3.4 MVP的优势与挑战
优势:
-
更好的解耦:View通过接口与Presenter交互
-
便于单元测试:业务逻辑在Presenter中,可以独立测试
-
职责清晰:Presenter专注于业务逻辑,View专注于界面
挑战:
-
接口爆炸 :每个View都需要定义接口
-
Presenter可能变得臃肿:复杂页面的Presenter可能包含大量逻辑
-
生命周期管理复杂:需要手动处理View的绑定和解绑
四、现代选择:MVVM模式
4.1 MVVM的设计理念
MVVM (Model-View-ViewModel)由微软提出,**在Android中结合Data Binding和LiveData等技术大放异彩,**这个后面的文章会着重介绍:
-
Model:与MVP相同,负责数据和业务逻辑
-
View:用户界面,观察ViewModel的数据变化
-
ViewModel:持有UI相关的数据,提供View需要的数据和命令
4.2 MVVM的关键技术
-
数据绑定:自动同步View和ViewModel的数据
-
观察者模式:View观察ViewModel的数据变化
-
生命周期感知:LiveData/Flow自动处理生命周期
4.3 MVVM的实现示例
4.3.1 UserViewModel.kt (ViewModel层)
Kotlin
// ViewModel
class UserViewModel : ViewModel() {
// 持有 Model 层引用
private val repository = UserRepository()
// LiveData观察用户数据
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
private val _error = MutableLiveData<String>()
val error: LiveData<String> = _error
// 业务逻辑方法
fun loadUser() {
// viewModelScope 自动管理协程生命周期
viewModelScope.launch {
try {
// 调用 Model 层获取数据
val user = repository.getUser()
_user.value = user
} catch (e: Exception) {
_error.value = "加载失败: ${e.message}"
}
}
}
}
ViewModel 关键点:
继承 ViewModel:生命周期比 Activity/Fragment 长
LiveData :实现观察者模式,数据变化时通知观察者
线程管理:后台操作避免阻塞 UI 线程
状态管理:管理加载、错误、成功等状态
4.3.2 UserActivity.kt (View层)
Kotlin
// Activity/Fragment作为View
class UserActivity : AppCompatActivity() {
private lateinit var binding: ActivityUserBinding
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Data Binding初始化
binding = DataBindingUtil.setContentView(this, R.layout.activity_user)
binding.lifecycleOwner = this
// 观察LiveData
viewModel.user.observe(this) { user ->
binding.user = user
}
viewModel.error.observe(this) { error ->
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
}
// 加载数据
viewModel.loadUser()
}
}
4.3.3 activity_user.xml
XML
<!-- Data Binding布局示例 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.example.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />
</LinearLayout>
</layout>
其实抛开Data Binding 不谈 也是标准的MVVM结构,这里只是锦上添花下。主要的是理解 ViewModel就可以了。
4.4 MVVM的优势与考量
优势:
-
双向数据绑定:减少模板代码
-
响应式编程:数据变化自动更新UI
-
更好的生命周期管理:LiveData自动处理
-
UI与业务逻辑彻底分离
考量:
-
调试困难:数据绑定错误可能难以追踪
-
学习曲线:需要理解响应式编程概念
-
过度使用数据绑定:可能导致性能问题
五、MVI ------ 2025 年的架构新范式
MVVM 并非终点。随着应用复杂度提升与声明式 UI 的普及,新一代架构思想正在融合演进:
4.1 MVI核心理念:单向数据流
MVI(Model-View-Intent)是一种响应式架构模式,强调单向数据流 和不可变状态。
4.2 MVI核心组件详解
4.2.1 Model - 应用状态
在MVI中,Model不是数据类,而是整个应用的状态。
Kotlin
// 1. 定义状态(Model) - 整个App的状态
data class CounterState(
val count: Int = 0, // 当前计数
val isLoading: Boolean = false, // 是否正在加载
val error: String? = null // 错误信息
)
4.2.2 View - 状态渲染器
View只做一件事:根据当前状态渲染界面。
Kotlin
// 2. Activity(View) - 渲染状态并发送Intent
class CounterActivity : AppCompatActivity() {
private lateinit var viewModel: CounterViewModel
private lateinit var countText: TextView
private lateinit var loadingIndicator: ProgressBar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_counter)
// 初始化ViewModel
viewModel = ViewModelProvider(this)[CounterViewModel::class.java]
// 绑定View
countText = findViewById(R.id.count_text)
loadingIndicator = findViewById(R.id.loading_indicator)
val incrementBtn: Button = findViewById(R.id.increment_btn)
val decrementBtn: Button = findViewById(R.id.decrement_btn)
val resetBtn: Button = findViewById(R.id.reset_btn)
val loadBtn: Button = findViewById(R.id.load_btn)
// 5. 观察状态变化并渲染
viewModel.state.onEach { state ->
render(state)
}.launchIn(lifecycleScope)
// 6. 设置点击监听,发送Intent
incrementBtn.setOnClickListener {
viewModel.processIntent(CounterIntent.IncrementIntent)
}
decrementBtn.setOnClickListener {
viewModel.processIntent(CounterIntent.DecrementIntent)
}
resetBtn.setOnClickListener {
viewModel.processIntent(CounterIntent.ResetIntent)
}
loadBtn.setOnClickListener {
viewModel.processIntent(CounterIntent.LoadCountIntent)
}
}
// 7. 渲染函数:根据状态更新UI
private fun render(state: CounterState) {
// 更新计数显示
countText.text = "当前计数: ${state.count}"
// 控制加载指示器
loadingIndicator.visibility = if (state.isLoading) View.VISIBLE else View.GONE
// 显示错误信息
state.error?.let { error ->
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
}
}
}
4.2.3 Intent - 用户意图
Intent不是Android的Intent,而是用户意图的抽象。
java
// 3. 定义意图(Intent) - 用户可能的操作
sealed class CounterIntent {
object IncrementIntent : CounterIntent() // 点击增加按钮
object DecrementIntent : CounterIntent() // 点击减少按钮
object ResetIntent : CounterIntent() // 点击重置按钮
object LoadCountIntent : CounterIntent() // 加载保存的计数
}
4.2.4 ViewModel - Reducer概念
Reducer是纯函数,接收当前状态和Intent,返回新状态。
Kotlin
当前状态 + Intent → Reducer → 新状态
Kotlin
// 3. ViewModel - 处理Intent并管理状态
class CounterViewModel : ViewModel() {
// 当前状态
private val _state = MutableStateFlow(CounterState())
val state: StateFlow<CounterState> = _state
// 处理用户意图
fun processIntent(intent: CounterIntent) {
// 根据不同的Intent,生成新的状态
val newState = when (intent) {
is CounterIntent.IncrementIntent -> {
// 当前计数 + 1
_state.value.copy(
count = _state.value.count + 1,
error = null
)
}
is CounterIntent.DecrementIntent -> {
// 当前计数 - 1(但不小于0)
val newCount = if (_state.value.count > 0) {
_state.value.count - 1
} else {
0
}
_state.value.copy(
count = newCount,
error = null
)
}
is CounterIntent.ResetIntent -> {
// 重置为0
_state.value.copy(
count = 0,
error = null
)
}
is CounterIntent.LoadCountIntent -> {
// 模拟加载数据
_state.value.copy(isLoading = true)
// 模拟网络请求(2秒后完成)
viewModelScope.launch {
delay(2000) // 模拟网络延迟
// 模拟加载到的数据
val savedCount = 5
_state.value = _state.value.copy(
count = savedCount,
isLoading = false,
error = null
)
}
// 立即返回加载中的状态
_state.value.copy(isLoading = true)
}
}
_state.value = newState
}
}
通过这个简单例子,可以看到MVI的三个核心:
Model就是状态
不是数据类,是整个UI的状态
包含所有UI需要的信息
Intent是用户意图
不是Android的Intent
是用户操作的抽象表示
View只做两件事
发送Intent(用户操作)
根据状态渲染UI
六、总结:架构演进的本质是"状态管理"的进化
| 维度 | MVC | MVP | MVVM | MVI(2025) |
|---|---|---|---|---|
| 状态持有者 | Activity | Presenter | ViewModel | StateFlow |
| UI 更新方式 | 手动调用 | 回调接口 | 观察数据 | 响应状态 |
| 生命周期管理 | 手动 | 手动(易错) | 自动 | 自动 |
| 可测试性 | 差 | 好 | 极好 | 极好 |
| 核心哲学 | 分离职责 | 彻底解耦 | 数据驱动 | 单向数据流 |