什么是Flutter中的MVVM?
MVVM拆解来说就是三个部分:
- Model
数据模型。通常来说,Model中保存了相关业务的数据,比如说用户(User),它其中包含id
、name
、password
。它就是一个Model。 - View
视图。通俗讲就是展示给用户的界面及控件,比如Flutter中参与界面展示的Widget。为什么我们要强调参与界面展示的Widget呢?因为在Flutter中几乎所有的东西都可以理解为Widget。 - ViewModel
负责实现View与Model的交互。这个是最关键的部分,ViewModel将视图和数据模型进行解耦,并且负责他们之间的交互。简单讲就是所有的业务逻辑都由它负责,而不是将业务逻辑和View都糅合在一起。
Flutter中的MVVM模式的几种方式
在不使用任何第三方包的时候,官方也提供了不错的选择,那就是StatefulWidget
,当我们需要改变状态来刷新UI时,只需要调用setState()
方法。
这种方法简单直接,而且也可以理解为一种MVVM模式,只不过View和Model仍然耦合在一起,ViewModel并没有承担起它应有的角色。随着我们的工程变得越来越大时,代码里的setState()
就会变得越来越多,显得非常混乱,并且有时候会忘记调用setState()
,导致浪费很多时间来定位问题。
官方早期也提供的一种状态管理模式叫做BLOC
。这种方式依赖于第三方包rxDart
,以流(Stream)的方式很好地解决了setState()
的问题。但是这种学习难度较大,对Flutter的新手并不友好。后来出现了一种第三方库Provider
,这是一种先进的状态管理和依赖注入的工具,并且易于学习和理解,所以目前官方也推荐首选Provider
。
本文我们也是主要介绍如何使用Provider
来实现MVVM模式。
其中定义的baseModel 实现 ChangeNotifier 实时对数据进行更新后通知 ,里面存放数据请求时,界面如何展示,请求结束后 界面如何提示等 类似于 dialog的展示和销毁,还有实现notifyListeners 判断界面是否销毁,数据是否刷新
其中的定义的BaseView
import 'package:flutter/material.dart';
import 'package:flutter_provider_mvvm/viewmodels/base_model.dart';
import 'package:provider/provider.dart';
//baseview 就是一个组件weight
class BaseView<T extends BaseModel> extends StatefulWidget {
final Widget Function(BuildContext context, T model, Widget child) builder;
final T model;
final Widget child;
final Function(T) onModelReady;
BaseView({Key key, this.model, this.builder, this.child, this.onModelReady}) : super(key: key);
@override
_BaseViewState<T> createState() => _BaseViewState<T>();
}
class _BaseViewState<T extends BaseModel> extends State<BaseView<T>> {
T model;
@override
void initState() {
//方便初始化 一些操作,类似于刚进页面需要网络请求等
// 为什么这里我们需要使用StatefulWidget呢?因为我们需要在initState()在所有的子类中给出初始化的机会。
// 在所有需要应用MVVM模式的Widget都可以继承这个基类,传入ChangeNotifierProvider所需要的参数,其中包括viewModel,builder,child,还有初始化时的回调方法onModelReady()。
model = widget.model;
if (widget.onModelReady != null) {
widget.onModelReady(model);
}
super.initState();
}
//ChangeNotifierProvider<T extends ChangeNotifier> 实时通知
//通过Consumer 内部结构 进行接收
/**
* class Consumer<T> extends SingleChildStatelessWidget {
/// {@template provider.consumer.constructor}
/// Consumes a [Provider<T>]
/// {@endtemplate}
Consumer({
Key key,
@required this.builder,
Widget child,
}) : assert(builder != null),
super(key: key, child: child);
/// {@template provider.consumer.builder}
/// Build a widget tree based on the value from a [Provider<T>].
///
/// Must not be `null`.
/// {@endtemplate}
final Widget Function(BuildContext context, T value, Widget child) builder;
@override
Widget buildWithChild(BuildContext context, Widget child) {
return builder(
context,
Provider.of<T>(context),
child,
);
}
}
*/
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<T>(
child: Consumer<T>(
builder: widget.builder,
child: widget.child,
),
create: (BuildContext context) {
return model;
},
);
}
}
更详细介绍
https://examplecode.cn/2020/05/09/flutter-provider-mvvm/