时间: 2020-08-31|tag: 37次围观|0 条评论

1. Flutter 结合 google MVP 架构的理解

在Android 应用开发中,google 官方就给出了对应的demo 展示了mvp的结构。

google demo地址: https://github.com/googlesamples/android-architecture

mvp 的项目结构意为把 UI层和数据层进行分割,让各个层级,做对应的事情,降低耦合程度,同时提高代码可阅读性。

下图可以大概了解m-v-p 的结构关系:

Flutter  MVP实践插图
在这里插入图片描述

针对Flutter 其实也可以进行对应的mvp架构

Flutter的mvp 架构中,View层就有所改变了,Android中是Activity ,而Flutter中就变成了 State ,为什么是State 而不是StatefulWidget 呢?

其实最主要一点就是Widget的状态表现都在State中体现,也就是说Widget的生命周期都State中。在处理业务逻辑的时候,也是离不开Widget的生命周期的,也就是离不开State的。所以State 作为View层是更加合理的。

而P层和M层其实就和Android 的MVP 没有什么区别了。

来个简单的的项目结构:

  • app_views : 页面,业务相关
    • base:基类
    • contract:接口文件
    • model:数据层文件
    • presenter:P层文件
    • views: 页面Widget文件
  • core :数据库,网络请求相关
  • utils: 工具类
  • widget: 独立控件
  • main.dart :应用入口
Flutter  MVP实践插图1
在这里插入图片描述

2. View--Presenter层构造

V-P层,更多是相互调用,View层处理UI展示的逻辑,业务的逻辑处理交给P层, P层处理业务逻辑,处理完进行回调给View层进行UI展示。

A. 基类

首先针对State 封装一个BaseState。BaseState 支持泛型接收 StatefuleWidget, 同时接受P层的接口。接收的 StatefuleWidget 是原来的State需要的。

BaseState

  1. 对State 的 build 方法进行一个简单封装,子类只要实现 buildViews 即可。
  2. 然后就是 presenter ,通过getPresenter ,让子类进行实例化。
  3. initState 状态也进行简单封装,获取到presenter实体,并赋值给mPresenter。同时抛出一个initViewState给子类去调用。
    View(State)层 就可以通过 mPersenter 调用 P层提供的接口了。
abstract class BaseState<T extends BaseStatefulWidget, E extends IPresenter> extends State<T> {  E mPresenter;  @override  void initState() {    mPresenter = getPresenter();    initViewState();    super.initState();  }  @override  Widget build(BuildContext context) {    return buildViews(context);  }  E getPresenter();  void initViewState();  Widget buildViews(BuildContext context);}

BasePresenter:

  1. 泛型接收View(State)层的接口
  2. 构造方法接收 View (State)实体, 赋值给 view 。方便调用View层接口

ps :其他代码忽略,其实处理M层数据需要的封装

abstract class BasePresenter<T extends IView> extends IPresenter {    T view;    BasePresenter(IView v):view = v;        handleError(error, errorCallback callback) {        HttpIOException exception = error as HttpIOException;        //TODO 可以对报错结果进行一轮处理,例如进行Toast 提示或者其他操作        callback(exception);    }}typedef errorCallback = void Function(HttpIOException error);

IContract :
这个文件比较简单,就是两个接口封装. 上面 BaseState ,BasePresenter 都会对 这两个接口文件进行继承实现。

abstract class IView {}abstract class IPresenter {}

B. 实现类

基类已经做了基本的封装,下面就是看看具体看看实现层面是怎么样的。

首先来个V-P的接口文件:

HomePageContract:
比较简单,继承IView 以及 IPresneter

abstract class IHomeView extends IView{  updateView();}abstract class IHomerPresenter extends IPresenter{  getData();}

_HomePageState:

首先是继承BaseState , 泛型接收 StatefulWidget 以及 IHomerPresenter ,同时实现了 IHomeView接口
BaseState,有几个方法需要在这里复写:

  1. getPresenter 获取Presenter 实体
  2. initViewState 对应 State的initState
  3. buildViews 对应 State的 build
class _HomePageState extends BaseState<HomePage, IHomerPresenter> implements IHomeView{  int _counter = 0;  @override  updateView() {  }  @override  IHomerPresenter getPresenter() {    return new HomePagePresenter(this);  }  @override  void initViewState() {  }  @override  Widget buildViews(BuildContext context) {    return new Scaffold(      appBar: new AppBar(        title: new Text(widget.title),      ),      body: new Center(        child: new Column(          mainAxisAlignment: MainAxisAlignment.center,          children: <Widget>[            new Text(              'You have pushed the button this many times:',            ),            new Text(              '$_counter',              style: Theme.of(context).textTheme.display1,            ),          ],        ),      ),      floatingActionButton: new FloatingActionButton(        onPressed: _incrementCounter,        tooltip: 'Increment',        child: new Icon(Icons.add),      ),    );  }}

HomePagePresenter :

presenter 继承 BasePresenter,泛型接收IHomeView,实现 IHomerPresenter 接口。

这里比较简单:

  1. 构造方法,传入View 接口,通过IView 就可以调用V层的UI了。 在构造时候,同时进行了M层的实例化
  2. getData是对接口文件 IHomePresenrer的实现,供View层调用。
class HomePagePresenter extends BasePresenter<IHomeView> implements IHomerPresenter{  IHomePageModelService homePageModelService;  HomePagePresenter(IHomeView v) : super(v) {    homePageModelService = new HomePageModel();    //可以建立多个 model 进行调用  }  @override  getData() async{    homePageModelService.getHomePageInfo("Tom", 18)        .then((data){      print("code:" + data.code.toString());      print("message:" + data.message);      print("time:" + data.payload.toString());    }).catchError((error) => handleError(error,(ioError){      print(ioError.message);    }));  }}

到此为止, _HomePageState 就通过IPresenter 接口持有了presenter的实体,可以对P层进行逻辑操作。同时HomePagePresenter 也通过 IView ,可以回调给 State 进行UI更新了。


3. Model层

model 层的意义在于是处理数据,包括网络数据,本地数据库数据等。

在上面的 HomePagePresenter , 构造方法进行了 一个HomePageModel的实例化。P层 和 M层之间,为什么不采用V-P层的接口形式呢?

  1. 出于P 层 会出现 一对多个 Model的情况。使用接口的形式会有比较大的限制。
  2. 出于dart 中 Future,Streams是天然的函数式编程方式,可以轻松的解决回调的情况。

出于这两个考虑,直接实例化Model更合理。

下面是具体的代码:
BaseService :

这个基类很简单,主要是针对网络层面的基类,在构造函数中,进行实例化了一个http的工具类。(后面的文章 httpUtil的分拆)

class BaseService {  static const String TAG = "Xuan_service";  HttpUtil httpUtil;  BaseService() : httpUtil = HttpUtil();}

HomePageContract

在原来 IHomeView,IHomerPresenter 的基础上,添加 IHomePageModelService。提供给P层调用

abstract class IHomeView extends IView{  updateView();}abstract class IHomerPresenter extends IPresenter{  getData();}abstract class IHomePageModelService{  Future<HomePageResp> getHomePageInfo(String userName, int age);  Future<dynamic> setARequest();  Future<dynamic> setBRequest ();}

HomPageModel

HomPageMode l继承 BaseService, 实现IHomePageModelService接口。
IHomePageModelService 提供了三个接口给P层调用。
对三个接口进行了一一实现。都是通过httpUtil 进行了网络数据的获取。
返回的是 Future 。这样P层可以直接拿到 Future对象,以及数据结果。不需要通过接口回调到P层。

Future 其实典型的函数式编程,和Android 的RxJava 比较像。

class HomePageModel extends BaseService implements IHomePageModelService {    HomePageReq getRequestData() {    return new HomePageReq(deviceId: "dd"        , userData: new UserData(name: "jack",age: 16));  }  @override  Future<HomePageResp> getHomePageInfo(String userName, int age) {    return httpUtil.post("getServerTimestampdd", getRequestData())        .then((resp) {          //这里可以做想要的转换,也可以什么都不做           HomePageResp result = new HomePageResp.fromJson(resp);           return result;        });  }  ///多个请求,异步进行,最后进行统一then处理,结果是顺序的,但是获取是异步的。并行关系  @override  Future<dynamic> setARequest() {    Future future1 = httpUtil.post("getServerTimestamp",getRequestData())        .then((dynamic resp){          print("1" + resp);          return resp;        });    Future future2 =  httpUtil.post("getServerTimestamp", getRequestData())        .then((dynamic resp) {      //这里可以做一层你想要的转换      print("2" +resp);      return resp;    });    return Future.wait([future1,future2])        .then((List t){      print(t);      return "test";    }).catchError((e){      print(e);    });  }  ///多个请求,一个接一个, 串联关系  @override  Future<dynamic> setBRequest() async {   var data1 = await httpUtil.post("getServerTimestamp","");   var data2 = await httpUtil.post("getServerTimestamp", data1);   return data2;  }}

小结

这个是简单的 MVP 结构。V-P层通过接口相互调用,P 层直接调用M层实体,通过Future进行响应结果。P可以使用多个Model的相关调用。

上面的HomePageModel 中其实还有其他的封装, 例如 HttpUtil 是对 dio 进行了一个简单的封装。而使用json转对象,利用了json_serializable。这个后面在单独记录下来。

文章转载于:https://www.jianshu.com/p/4639dd640249

原著是一个有趣的人,若有侵权,请通知删除

本博客所有文章如无特别注明均为原创。
复制或转载请以超链接形式注明转自起风了,原文地址《Flutter MVP实践
   

还没有人抢沙发呢~