什么是Flutter中的MVVM?

MVVM拆解来说就是三个部分:

  • Model
    数据模型。通常来说,Model中保存了相关业务的数据,比如说用户(User),它其中包含idnamepassword。它就是一个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/

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐