1.Mvvm简单介绍
学习完Flutter后在准备上手进行项目搭建的时候,我突然有一个很大的疑问,就是怎么使用Mvvm进行开发?网上查询了一下相关文章后,也没有一个很详细具体的方案,也有部分方案是基于一些热门的第三方框架结合而成的,万一这些框架以后不维护了那怎么办,需要有一套原生的方案,经过资料和博客的查阅,自己实践了一套Mvvm方案分享给大家,如果大家在阅读的过程中发现有不对的地方也希望大家可以留言提出,如果觉得对你有帮助也不要吝啬点赞、收藏~
如果大家对Mvvm已经很熟悉了,可以直接跳到第2点开始阅读具体实践。
1.1 为什么需要Mvvm?
Mvvm其实在移动端开发已经是老生常谈的知识了,我现在提出一个疑问,如果我们不使用Mvvm模式,我们的代码会是怎么样的样子?没错,无论是UI代码,还是业务逻辑都会耦合在一个文件或者类里面,当经过不断地迭代,你会发现这个类会发展成成千上万行代码,耦合还特别严重,当你想改某个点的时候,极有可能牵一发动全身,那么这个时候就需要一种方式,将代码分好类,并且规定类与类之间的交互与通信方式,这样分好类的代码才会更加容易扩展、复用还有阅读。
1.2 Mvvm介绍
首先我不会以十分学术性的去讲述Mvvm,避免讲得太过笼统,会偏直白简单的去描述一下Mvvm,有什么不对的地方希望大家可以友善的提出。
其实Mvvm是经过发展后得出的产物,它的前身是Mvc、Mvp,但是基于篇幅,这里不会去介绍Mvc和Mvp,我们只需要知道Mvc和Mvp也是代码分类的一种思想,接下来会简单介绍Mvvm模式,首先上一幅图:
我们从图中可以看出2个信息:
- 代码是如何分类的
- 每类代码他们是如何通信交互的
我们可以看出,Mvvm将代码分成三类,按照我的理解分为以下三类:
- View(视图代码)
毫无疑问,View就是用于编写视图相关的代码的一类,在Flutter中典型的实现就是我们的StatefulWidget与StatelessWidget,我们通常会将代码写在其中,所以在StatefulWidget与StatelessWidget就是我们的View层,我们会将UI代码写在其中,需要注意的是,View层中不会直接跟Model进行通讯(比如网络请求等),View会通过ViewModel进行对Model的获取。
- ViewModel(逻辑代码)
ViewModel存在目的在于抽离View中展示的业务逻辑,主要负责业务逻辑的处理,同时与 Model 层 和 View层交互。
- Model(数据)
负责与数据库和网络层通信,获取并存储数据。与MVP的区别在于Model层不再通过回调通知业务逻辑层数据改变,而是通过观察者模式实现。
看到这里,估计大家会对View-ViewModel-model是什么,应该有一个简单的认识了,但是对他们具体怎么交互通信可能还是有点抽象,我们可以从图中看到:
- 实线部分:View层通过ViewModel层对Model进行操作
- 虚线部分:Model层通过ViewModel层对View层进行驱动
所以View与Model不会直接关联,会通过ViewModel这一个中枢机构去交互,ViewModel本身处理业务逻辑的同时也会处理Model与View的通信和事件。
这样做有个好处就是,他们的流向十分清晰,开发者会知道,View产生任何的事件,都一定是流向ViewModel的,View接收任何事件,都是从ViewModel接收的。
MVVM架构的本质是数据驱动,它的最大的特点是单向依赖。MVVM架构通过观察者模式让ViewModel与View解耦,实现了View依赖ViewModel,ViewModel依赖Model的单向依赖。
2.Mvvm在Flutter中的实现
了解Mvvm之后,接着的具体的步骤就是以下几步:
- 定义ViewModel层
- 定义View层
- 定义Model层
- 处理View与ViewModel的双向数据绑定(重点)
2.1 定义ViewModel
ViewModel我这边只定义了ViewModel的生命周期,在我的设计下面,ViewModel的生命周期是依赖View层的,所以先定义与Widget的生命周期一致的函数,但是我目前暂时先定义onCreate(对应initState)与onDispose(对应Widget的销毁)
/// 基类
abstract class BaseViewModel extends ChangeNotifier {
BaseViewModel() ;
//尽量在onCreate方法中编写初始化逻辑
onCreate();
//对应的widget被销毁时
onDispose() {
}
}
/// 页面继承的ViewModel
abstract class PageViewModel extends BaseViewModel {
PageViewModel(super.context);
onCreate() {
}
}
///
ViewModel中我区分了BaseViewModel与PageViewModel,后面还会有WidgetViewModel,趁早区分一下继承的关系,后面好扩展。
2.2 View层的封装
大家都知道,Flutter中UI是离不开Widget的,Flutter中的Widget分两种,一种是无状态控件(StatelessWidget),一种是有状态控件(StatefulWidget),无状态控件自身并没有刷新UI的功能,所以我们重点还是关注对StatefulWidget的封装,但是封装的关键还是其State,StatefulWidget本身没有太多逻辑
///定义ViewModelWidget基类
abstract class BaseViewModelWidget<VM extends BaseViewModel> extends StatefulWidget {
const BaseViewModelWidget({
Key? key}) : super(key: key);
BaseViewModelState<BaseViewModelWidget,VM> createState();
}
///定义ViewModelState(相关逻辑在这里)
abstract class BaseViewModelState<T extends StatefulWidget,
VM extends BaseViewModel> extends BaseState<T> {
///定义其ViewModel
late VM viewModel;
///进行初始化ViewModel相关操作
void initState() {
super.initState();
///初始化ViewModel,并同步生命周期
viewModel = initViewModel();
//延迟初始化,避免在initState中对context进行了操作,此时context可能为空
Future.delayed(Duration.zero).then((value) {
///此刻可以进行一些绑定操作
initObserver();
///调用ViewModel的生命周期,此时可以进行一些初始化,比如网络请求等
viewModel.onCreate();
///Widget本身的一些数据初始化,比如参数之类的
initData();
});
}
/