驿路星辰的博客

Flutter中使用Provider实现MVVM架构

Word count: 871Reading time: 4 min
2020/08/29 Share

MVVM介绍

MVVM架构分为M(Model)、V(View)、VM(ViewModel)三个部分,他们分别处理自己的分工,在View和Model之间使用ViewModel作为中介者,使View和Model不受业务逻辑影响。

Model: 模型层,处理Api数据、模型相关业务

View: 视图层,UI呈现、使用者互动等。

ViewModel: 视图模型,处理逻辑、将数据绑定给View展示。

Controller: 负责主要事情就是将View和ViewModel进行绑定,生命周期管理

MVVM的核心思想即:通过ViewModel在View和Model之间建立一个连接,实现View和Model的双向绑定。


Flutter中的MVVM应用

Flutter中通过Provider进行状态管理,来实现MVVM。在MVVM的原本的三个部分添加Services层,方便业务的分离.

Services: 是获取数据接口(服务器Server 或者 本地Store)

Model: 主要负责转换模型

View: 主要负责呈现UI,通过ViewModel获取数据并展示

ViewModel: 处理业务逻辑,将数据绑定给View展示

Controller:一般是stf,负责主要事情就是将View和ViewModel进行绑定,生命周期管理


1.定义模型

将网络请求回来的数据转换为对应的模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class DeviceOnlineStatusData {
String deviceId;
String deviceType;
String loginTime;
String createdAt;

DeviceOnlineStatusData({this.deviceId, this.deviceType, this.loginTime, this.createdAt});

DeviceOnlineStatusData.fromJson(Map<String, dynamic> json) {
deviceId = json['device_id'];
deviceType = json['device_type'];
loginTime = json['login_time'];
createdAt = json['created_at'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['device_id'] = this.deviceId;
data['device_type'] = this.deviceType;
data['login_time'] = this.loginTime;
data['created_at'] = this.createdAt;
return data;
}
}

2.定义ViewModel

这个ViewModel主要负责把请求回来的数据进行处理,并通知View层更新数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class DeviceOnlineStatusVM extends ChangeNotifier {
bool isPcLogin = false;
bool isPadLogin = false;

String pcDeviceID = '';
String pcDeviceType = '';

String padDeviceID = '';
String padDeviceType = '';

setOnlineStatus(List<DeviceOnlineStatusData> statusData) {
init();
isPcLogin = true;
pcDeviceID = item.deviceId;
pcDeviceType = item.deviceType;
isPadLogin = true;
padDeviceID = item.deviceId;
padDeviceType = item.deviceType;
notifyListeners();
}

void init() {
isPcLogin = false;
isPadLogin = false;
pcDeviceID = '';
pcDeviceType = '';
padDeviceID = '';
padDeviceType = '';
}
}

3.定义网络请求类

网络请求将请求回来的数据转换为模型,并更新ViewModel数据。通过extension进行横向拓展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
extension DeviceOnlineStatusServices on DeviceOnlineStatusVM {
//获取设备状态
Future<void> getOnlineStatusServices() async {
HttpResp httpResp = await HttpApi().getOnlineStatus();
if (httpResp.code == 0) {
List jsonList = httpResp.value;
List<DeviceOnlineStatusData> statusData = jsonList.map((e) => DeviceOnlineStatusData.fromJson(e)).toList();
setOnlineStatus(statusData);
}
}

//更新设备状态
Future<void> setOnlineStatusServices(String deviceID, String deviceType) async {
HttpResp httpResp = await HttpApi().postOnlineStatus(deviceID, deviceType);
if (httpResp.code == 0) {
List jsonList = httpResp.value;
List<DeviceOnlineStatusData> statusData = jsonList.map((e) => DeviceOnlineStatusData.fromJson(e)).toList();
setOnlineStatus(statusData);
}
}
}

4.View数据展示层

单独抽出View层,View用来渲染数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

class DeviceOnlineStatusView extends StatelessWidget {
const DeviceOnlineStatusView({Key key, this.viewModel}) : super(key: key);
final DeviceOnlineStatusVM viewModel;
@override
Widget build(BuildContext context) {
return Flex(
direction: Axis.vertical,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Image.asset("assets/images/im_device_pc.png", width: 178, height: 92)],
),
const SizedBox(height: 14.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextImageButtonWidget(
text: "退出",
normalImage: "im_device_back.png",
disableImage: "im_device_back_disable.png",
buttonEnable: viewModel.isPcLogin,
onTapCallBack: () {
Utils.showCommonDialog(context: context, content: '是否退出电脑登录?').then((value) async {
if (value) {
viewModel
.setOnlineStatusServices(viewModel.pcDeviceID, viewModel.padDeviceType)
.then((value) {
if (!viewModel.isPadLogin && !viewModel.isPcLogin) {
Utils.popPage();
}
});
}
});
}),
],
),
],
),
],
);
}
}

5.Controller用来将viewModel绑定View,并且管理生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class DeviceOnlineStatusPage extends StatefulWidget {
const DeviceOnlineStatusPage({
Key key,
this.title,
this.deviceOnlineStatusVM,
}) : super(key: key);

final String title;

final DeviceOnlineStatusVM deviceOnlineStatusVM;

@override
State<StatefulWidget> createState() => _DeviceOnlineStatusPage();
}

class _DeviceOnlineStatusPage extends State<DeviceOnlineStatusPage> {
@override
void initState() {
// 获取接口数据
widget.deviceOnlineStatusVM.getOnlineStatusServices();

super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: NavigationAppBar(title: widget.title),
body: ChangeNotifierProvider.value(
value: widget.deviceOnlineStatusVM,
child: Consumer<DeviceOnlineStatusVM>(
builder: (context, _viewModel, _) {
return DeviceOnlineStatusView(viewModel: _viewModel);
},
),
),
);
}
}
CATALOG
  1. 1. MVVM介绍
  2. 2. Flutter中的MVVM应用
    1. 2.1. 1.定义模型
    2. 2.2. 2.定义ViewModel
    3. 2.3. 3.定义网络请求类
    4. 2.4. 4.View数据展示层
    5. 2.5. 5.Controller用来将viewModel绑定View,并且管理生命周期