编辑
2026-01-06
移动端
00

目录

MVVM 架构模式详解
一、MVVM 基本概念
二、三层架构详解
1. Model 层(数据层)
2. View 层(视图层)
3. ViewModel 层(视图模型层)
三、数据流向图
四、完整示例:数据加载流程
场景:用户打开应用,加载测试数据文件列表
步骤 1: View 初始化并请求数据
步骤 2: ViewModel 转发请求到 Model
步骤 3: Model 加载数据
步骤 4: ViewModel 更新 LiveData
步骤 5: View 自动更新 UI
五、MVVM 的核心机制
1. 数据绑定(Data Binding)
2. 单向数据流
3. 生命周期管理
六、MVVM vs 其他架构模式
MVVM vs MVP
MVVM vs MVC
七、MVVM 的优势
1. 解耦
2. 响应式更新
3. 生命周期感知
4. 可测试性
5. 代码复用
八、MVVM 的注意事项
1. ViewModel 不应持有 View 引用
2. 避免在 ViewModel 中处理 UI 相关逻辑
3. 合理使用 LiveData
九、项目中的实际应用总结
你的项目架构:
关键代码模式:
十、总结

MVVM 架构模式详解

一、MVVM 基本概念

MVVM (Model-View-ViewModel) 是一种架构设计模式,将应用程序分为三个主要部分:

  • Model(模型): 数据和业务逻辑
  • View(视图): UI 界面
  • ViewModel(视图模型): View 和 Model 之间的桥梁,负责数据绑定和业务逻辑处理

二、三层架构详解

1. Model 层(数据层)

职责

  • 管理数据(本地数据库、网络数据、缓存等)
  • 处理业务逻辑
  • 提供数据访问接口

在你的项目中的体现

java
// TestModel.java - Model 层 public class TestModel implements TestManager.ILoadDataCallBack { private IDataFileViewModel mIDataFileViewModel; // 单例模式,管理数据访问 public static TestModel getInstance() { return SingleHolder.sInstance; } // 加载数据 public void load(String tag) { TestManager.getInstance().load(tag); } // 数据加载成功后的回调 @Override public void loadDataFileSuccess() { // 通知 ViewModel 数据已更新 mIDataFileViewModel.onDataFileListUpdate( TestManager.getInstance().getDataFileList() ); } }

特点

  • 不直接与 View 交互
  • 通过回调接口通知 ViewModel
  • 封装数据访问逻辑(TestManager)

2. View 层(视图层)

职责

  • 显示 UI 界面
  • 处理用户交互
  • 观察 ViewModel 的数据变化并更新 UI

在你的项目中的体现

java
// TestCaseListFragment.java - View 层 public class TestCaseListFragment extends Fragment { private DataFileViewModel viewModel; // 持有 ViewModel 引用 private DataFileAdapter adapter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 获取 ViewModel 实例 viewModel = new ViewModelProvider(requireActivity()) .get(DataFileViewModel.class); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 观察数据文件列表的变化 viewModel.getCurrentDataFiles().observe( getViewLifecycleOwner(), dataFiles -> { // 当数据变化时,自动更新 UI if (dataFiles != null) { adapter.updateData(dataFiles); updateStatistics(dataFiles); } } ); // 观察正在执行的文件 viewModel.getExecutingDataFile().observe( getViewLifecycleOwner(), script -> { if (script != null) { // 更新对应项的 UI int position = adapter.getDataFiles().indexOf(script); if (position != -1) { adapter.notifyItemChanged(position); } } } ); } // 用户点击执行按钮 @Override public void onExecuteClick(DataFileItem dataFileItem) { // 通过 ViewModel 执行操作 long executionId = viewModel.startTestSync(); // ... } }

特点

  • 只负责 UI 展示和用户交互
  • 通过 observe() 观察 ViewModel 的数据
  • 不直接操作 Model
  • 生命周期感知(使用 getViewLifecycleOwner()

3. ViewModel 层(视图模型层)

职责

  • 为 View 提供数据
  • 处理 View 的交互逻辑
  • 与 Model 层通信
  • 管理 UI 相关的状态(加载、错误等)

在你的项目中的体现

java
// DataFileViewModel.java - ViewModel 层 public class DataFileViewModel extends ViewModel implements IDataFileViewModel { // 使用 LiveData 暴露数据给 View private final MutableLiveData<List<DataFileItem>> _currentDataFiles = new MutableLiveData<>(); public LiveData<List<DataFileItem>> currentDataFiles = _currentDataFiles; private TestModel testModel; // 持有 Model 引用 // 加载数据 public void load(String tag) { testModel = TestModel.getInstance(); testModel.setIDataFileViewModel(this); // 设置回调 testModel.load(tag); // 请求 Model 加载数据 testModel.update(); } // Model 层回调:数据更新 @Override public void onDataFileListUpdate(List<DataFileItem> dataFileList) { // 更新 LiveData,自动通知所有观察者(View) _currentDataFiles.postValue(dataFileList); loading.postValue(false); } // View 层调用:执行测试 public long startTestSync() { return testModel.startTestSync(); } }

特点

  • 不持有 View 的引用(避免内存泄漏)
  • 使用 LiveData 实现响应式数据流
  • 实现回调接口,接收 Model 的通知
  • 生命周期独立于 View(Activity/Fragment 重建时保留)

三、数据流向图

┌─────────────────────────────────────────────────────────┐ │ MVVM 数据流向 │ └─────────────────────────────────────────────────────────┘ 用户操作 ↓ ┌──────┐ │ View │ (Fragment/Activity) └──┬───┘ │ 1. 用户点击按钮 │ 2. 调用 ViewModel 方法 ↓ ┌─────────────┐ │ ViewModel │ (DataFileViewModel) └──┬──────┬───┘ │ │ │ 3. │ 4. 通过回调接口 │ 调用 │ 接收数据更新 ↓ ↓ ┌──────┐ ┌──────┐ │Model │ │Model │ (TestModel) └──┬───┘ └──┬───┘ │ │ │ 5. │ 6. 数据加载完成 │ 加载 │ 回调 ViewModel │ 数据 │ ↓ ↓ ┌─────────────┐ │ Data Source │ (TestManager/网络/数据库) └─────────────┘ 反向数据流(响应式更新): Model → ViewModel → View (通过 LiveData)

四、完整示例:数据加载流程

场景:用户打开应用,加载测试数据文件列表

步骤 1: View 初始化并请求数据

java
// MainActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 1. 获取 ViewModel viewModel = new ViewModelProvider(this) .get(DataFileViewModel.class); // 2. 观察数据变化 viewModel.getCurrentDataFiles().observe(this, dataFiles -> { // 当数据到达时,自动更新 UI adapter.updateData(dataFiles); }); // 3. 请求加载数据 viewModel.load("remote"); }

步骤 2: ViewModel 转发请求到 Model

java
// DataFileViewModel.java public void load(String tag) { // 1. 获取 Model 实例 testModel = TestModel.getInstance(); // 2. 设置回调接口(用于接收数据) testModel.setIDataFileViewModel(this); // 3. 请求 Model 加载数据 testModel.load(tag); testModel.update(); }

步骤 3: Model 加载数据

java
// TestModel.java public void load(String tag) { // 委托给 TestManager 加载数据(可能是网络请求或数据库查询) TestManager.getInstance().load(tag); } // TestManager 异步加载数据后,通过回调通知 @Override public void loadDataFileSuccess() { // 数据加载成功,通知 ViewModel mIDataFileViewModel.onDataFileListUpdate( TestManager.getInstance().getDataFileList() ); }

步骤 4: ViewModel 更新 LiveData

java
// DataFileViewModel.java @Override public void onDataFileListUpdate(List<DataFileItem> dataFileList) { // 更新 LiveData,触发所有观察者 _currentDataFiles.postValue(dataFileList); loading.postValue(false); // 隐藏加载状态 }

步骤 5: View 自动更新 UI

java
// MainActivity.java 中的观察者自动被触发 viewModel.getCurrentDataFiles().observe(this, dataFiles -> { // 这里自动执行,更新 RecyclerView adapter.updateData(dataFiles); });

五、MVVM 的核心机制

1. 数据绑定(Data Binding)

LiveData 是 Android 中实现数据绑定的关键组件:

java
// ViewModel 中定义 private final MutableLiveData<List<DataFileItem>> _currentDataFiles = new MutableLiveData<>(); public LiveData<List<DataFileItem>> currentDataFiles = _currentDataFiles; // View 中观察 viewModel.getCurrentDataFiles().observe(lifecycleOwner, dataFiles -> { // 数据变化时自动执行 updateUI(dataFiles); });

优势

  • 自动更新:数据变化时 UI 自动更新
  • 生命周期感知:Activity/Fragment 销毁时自动取消观察
  • 线程安全:postValue() 可在后台线程调用

2. 单向数据流

用户操作 → View → ViewModel → Model → 数据源 ↓ UI 更新 ← View ← ViewModel ← Model ← 数据更新

特点

  • View 不直接操作 Model
  • ViewModel 作为中间层,控制数据流向
  • 数据流向清晰,易于调试

3. 生命周期管理

java
// ViewModel 生命周期独立于 View public class DataFileViewModel extends ViewModel { @Override protected void onCleared() { super.onCleared(); // Activity/Fragment 销毁时调用 // 清理资源,避免内存泄漏 testModel.clear(); } }

优势

  • Activity 旋转时,ViewModel 不会重建
  • 数据在配置变更时保留
  • 避免重复加载数据

六、MVVM vs 其他架构模式

MVVM vs MVP

特性MVVMMVP
View 与 Presenter/ViewModelView 观察 ViewModelView 持有 Presenter 引用
数据绑定LiveData/DataBinding手动调用 View 方法
耦合度低(View 不持有 ViewModel)中(View 持有 Presenter)
测试性高(ViewModel 独立测试)高(Presenter 独立测试)

MVVM vs MVC

特性MVVMMVC
ControllerViewModelController
View 职责仅 UI 展示UI + 部分逻辑
数据流向单向,清晰可能双向,复杂

七、MVVM 的优势

1. 解耦

  • View 和 Model 完全分离
  • View 不直接依赖 Model
  • 易于维护和测试

2. 响应式更新

  • 使用 LiveData 实现自动更新
  • 减少手动更新 UI 的代码
  • 数据变化时 UI 自动刷新

3. 生命周期感知

  • LiveData 自动处理生命周期
  • 避免内存泄漏
  • 配置变更时数据保留

4. 可测试性

  • ViewModel 可以独立测试(不依赖 View)
  • Model 可以独立测试(不依赖 View)
  • 易于编写单元测试

5. 代码复用

  • ViewModel 可以在多个 View 间共享
  • 业务逻辑集中在 ViewModel

八、MVVM 的注意事项

1. ViewModel 不应持有 View 引用

错误示例

java
public class DataFileViewModel extends ViewModel { private Activity activity; // 错误!会导致内存泄漏 }

正确做法

java
public class DataFileViewModel extends ViewModel { // 使用 LiveData 暴露数据,不持有 View 引用 private final MutableLiveData<List<DataFileItem>> _dataFiles = new MutableLiveData<>(); }

2. 避免在 ViewModel 中处理 UI 相关逻辑

错误示例

java
public void loadData() { // 不应该在 ViewModel 中处理 UI Toast.makeText(context, "Loading...", Toast.LENGTH_SHORT).show(); }

正确做法

java
// ViewModel 中 private final MutableLiveData<Boolean> loading = new MutableLiveData<>(); public void loadData() { loading.postValue(true); // ... } // View 中观察 viewModel.getLoading().observe(this, isLoading -> { if (isLoading) { showLoadingDialog(); } else { hideLoadingDialog(); } });

3. 合理使用 LiveData

  • 使用 postValue() 在后台线程更新
  • 使用 setValue() 在主线程更新
  • 避免在 ViewModel 中暴露 MutableLiveData

九、项目中的实际应用总结

你的项目架构:

┌─────────────────────────────────────┐ │ View 层 │ │ - MainActivity │ │ - TestCaseListFragment │ │ - DataFileAdapter │ └──────────────┬──────────────────────┘ │ observe LiveData │ 调用 ViewModel 方法 ↓ ┌─────────────────────────────────────┐ │ ViewModel 层 │ │ - DataFileViewModel │ │ - 管理 LiveData │ │ - 实现 IDataFileViewModel │ │ - 处理 UI 状态 │ └──────────────┬──────────────────────┘ │ 调用 Model 方法 │ 接收 Model 回调 ↓ ┌─────────────────────────────────────┐ │ Model 层 │ │ - TestModel (单例) │ │ - 封装业务逻辑 │ │ - 管理数据访问 │ │ - 回调 ViewModel │ └──────────────┬──────────────────────┘ │ 调用 Manager ↓ ┌─────────────────────────────────────┐ │ Data Source 层 │ │ - TestManager │ │ - 网络请求/数据库访问 │ └─────────────────────────────────────┘

关键代码模式:

  1. 观察数据变化
java
viewModel.getCurrentDataFiles().observe(lifecycleOwner, data -> { // 自动更新 UI });
  1. 请求数据
java
viewModel.load("remote");
  1. 处理用户操作
java
viewModel.startTestSync();
  1. Model 回调
java
@Override public void onDataFileListUpdate(List<DataFileItem> list) { _currentDataFiles.postValue(list); }

十、总结

MVVM 架构通过以下方式实现清晰的代码组织:

  1. 分离关注点:View 只负责 UI,ViewModel 处理逻辑,Model 管理数据
  2. 响应式编程:使用 LiveData 实现自动数据绑定
  3. 生命周期管理:ViewModel 独立于 View 的生命周期
  4. 易于测试:各层可以独立测试
  5. 代码复用:ViewModel 可以在多个 View 间共享

MVVM 架构使得:

  • UI 更新自动化(通过 LiveData 观察)
  • 数据加载流程清晰(View → ViewModel → Model)
  • 代码易于维护和扩展
  • 符合 Android 官方推荐的架构模式

本文作者:lixf6

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!