本文首发于公众号:移动开发那些事:Flutter 中的 MVVM 架构实现指南
1 MVVM架构
MVVM (Model-View-ViewModel) 是一种软件架构模式,它是 MVC(Model-View-Controller)和 MVP(Model-View-Presenter)的进化版本, 它将应用程序的用户界面(UI)逻辑与业务逻辑分离,通过 ViewModel 作为中间层连接 View 和 Model。

1.1 核心组件
Model:负责数据处理、业务逻辑和网络请求等,不直接与UI交互;View:UI界面,负责展示数据和接收用户输入,通过与ViewModel的绑定来进行UI的更新;ViewModel:连接View和Model的桥梁,处理视图逻辑并提供数据给View。
1.2 架构特点
- 双向数据绑定 :
View和ViewModel之间的数据变化会自动同步,减少了手动更新UI的代码; - 提高可测试性 :
ViewModel可以独立测试,无需依赖UI。 - 分离关注点:UI 逻辑和业务逻辑分离,提高代码可维护性和可测试性。
- 提高可维护性:代码的可读性和可维护性更高,适合大型复杂项目的开发;
1.3 适用场景
- 复杂 UI 应用:当界面逻辑复杂时,MVVM 能有效管理状态和数据流;
- 需要频繁更新 UI 的应用:双向数据绑定使数据更新更高效;
- 需要单元测试的项目 :
ViewModel的独立性使其易于测试;
2 简单架构示例
以一个简单的计数器的例子来说明如何来搭建一个MVVM的架构;
php
import 'package:flutter/material.dart';
// 步骤1:定义 Model: 负责数据处理
class CounterModel {
int _count = 0;
int get count => _count;
void increment() {
_count++;
}
void decrement() {
_count--;
}
}
// 步骤2:ViewModel: 连接 View 和 Model
class CounterViewModel with ChangeNotifier {
final CounterModel _model = CounterModel();
int get count => _model.count;
void increment() {
// 处理数据更新
_model.increment();
notifyListeners(); // 通知 View 更新
}
void decrement() {
// 处理数据更新
_model.decrement();
notifyListeners(); // 通知 View 更新
}
}
// 步骤3 View: UI 界面
class CounterScreen extends StatelessWidget {
final CounterViewModel _viewModel = CounterViewModel();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('MVVM 计数器')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 使用 ValueListenableBuilder 监听 ViewModel 变化,viewModel变化时,对应的页面也会同步刷新
ValueListenableBuilder(
valueListenable: _viewModel,
builder: (context, value, child) {
return Text(
'计数: ${_viewModel.count}',
style: TextStyle(fontSize: 24),
);
},
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _viewModel.decrement,
child: Text('减'),
),
SizedBox(width: 20),
ElevatedButton(
onPressed: _viewModel.increment,
child: Text('加'),
),
],
),
],
),
),
);
}
}
3 使用GetX框架实现MVVM架构
GetX 是 Flutter 中一个强大的轻量级框架,它简化了状态管理、路由和依赖注入等功能。下面是使用 GetX 实现相同计数器应用的示例:
php
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// 步骤1:定义 Model: 负责数据处理
class CounterModel {
int _count = 0;
int get count => _count;
void increment() {
_count++;
}
void decrement() {
_count--;
}
}
// 步骤2:ViewModel (在 GetX 中称为 Controller)
class CounterController extends GetxController {
final CounterModel _model = CounterModel();
// 使用 RxInt 实现响应式数据
final RxInt _count = 0.obs;
int get count => _count.value;
void increment() {
_model.increment();
_count.value = _model.count; // 更新响应式数据
}
void decrement() {
_model.decrement();
_count.value = _model.count; // 更新响应式数据
}
}
// 步骤3 : View: UI 界面
class CounterScreen extends StatelessWidget {
// 使用 Get.put() 初始化 Controller
final CounterController _controller = Get.put(CounterController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('GetX MVVM 计数器')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 使用 Obx 监听 Controller 中的响应式数据
Obx(() => Text(
'计数: ${_controller.count}',
style: TextStyle(fontSize: 24),
)),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _controller.decrement,
child: Text('减'),
),
SizedBox(width: 20),
ElevatedButton(
onPressed: _controller.increment,
child: Text('加'),
),
],
),
],
),
),
);
}
}
4 适用场景
| 场景类型 | 推荐方案 | 原因 |
|---|---|---|
| 小型应用/快速原型 | GetX | 开发速度快,代码少 |
| 中大型项目 | 原生 + Provider | 分层明确,长期维护性强 |
| 多平台代码共享 | 原生 + 抽象ViewModel | 业务逻辑与平台解耦 |
| 高频更新 | GetX | 性能优化,避免全页重建 |
5 总结
MVVM 架构模式在 Flutter 开发中非常有用,它可以帮助我们构建更清晰、更易维护的应用程序。在不使用第三方框架的情况下,我们可以通过ChangeNotifier 和 Stream 等机制实现 MVVM,但代码会相对复杂。而使用 GetX 这样的框架可以大大简化 MVVM 的实现,提供更简洁的代码和更好的开发体验。实际使用过程中,可以根据业务的复杂程度,团队熟练度,以及长期计划来决定使用哪个机制来实现MVVM架构;