如何在 Flutter 中使用 MVP 架构

在 Android 开发中有很多设计模式,从 MVC 到 MVP MVVM 等,而在 Flutter 中也可是使用 MVP 模式进行开发,在这篇文章中我们来看一下在 Flutter 中如何使用 MVP 模式开发应用.

MVP 模式主要包含三个部分

  • UI 层包含所有我们需要的 Widgets
  • Presenters 将连接 UI 层和数据层
  • Data 层包含所有我们的数据操作

最终的代码可以在这个仓库中获得 FlutterMvpArc

Data Layer

我们先来创建数据层,在 Flutter 项目的 lib 目录创建 data 目录,然后创建contact_data.dart 文件,在这个文件中我们写入下面的代码:

import 'dart:async';

class Contact {
  final String fullName;
  final String email;

  const Contact({this.fullName, this.email});

  Contact.fromMap(Map<String, dynamic> map)
      : fullName = "${map['name']['first']} ${map['name']['last']}",
        email = map['email'];
}

abstract class ContactRepository {
  Future<List<Contact>> fetch();
}

class FetchDataException implements Exception {
  String _message;

  FetchDataException(this._message);

  @override
  String toString() {
    return "Exception:$_message";
  }
}

在上面的代码中我们首先引入了 dart 异步执行库,然后创建了 Contact类,ContactRepository 接口,这个借口定义了fetch方法用来获取数据,最后自定义了FetchDataException异常.

Mock Repository

现在我们来创建第一个 ContactRepository 接口实现类,在 data 目录添加一个文件contact_data_mock.dart,这个类实现了ContactRepository接口,然后实现了fetch方法,返回我们模拟的数据.

import 'dart:async';
import 'contact_data.dart';

class MockContactRepository implements ContactRepository {
  @override
  Future<List<Contact>> fetch() => Future.value(kContacts);
}

const kContacts = const <Contact>[
  const Contact(
      fullName: 'Romain Hoogmoed', email: 'romain.hoogmoed@example.com'),
  const Contact(fullName: 'Emilie Olsen', email: 'emilie.olsen@example.com')
];

Random User Repository

我们的第二个ContactRepository实现类是 RandomUserRepository , 它将从网络获取数据;
在 data 目录我们创建一个contact_data_impl.dart 文件,然后添加下面的代码:

import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'contact_data.dart';

class RandomUserRepository implements ContactRepository {
  static const _kRandomUserUrl = 'http://api.randomuser.me/?results=15';
  final JsonDecoder _decoder = new JsonDecoder();

  @override
  Future<List<Contact>> fetch() {
    return http.get(_kRandomUserUrl).then((http.Response response) {
      final String jsonBody = response.body;
      final statusCode = response.statusCode;

      if (statusCode < 200 || statusCode >= 300 || jsonBody == null) {
        throw new FetchDataException(
            "Error while getting contacts [StatusCode:$statusCode, Error:${response.toString()}]");
      }

      final contactsContainer = _decoder.convert(jsonBody);
      final List contactItems = contactsContainer['results'];

      return contactItems
          .map((contactRaw) => new Contact.fromMap(contactRaw))
          .toList();
    });
  }
}

为了使用网络请求,我们先引入了package:flutter/http.dart包.在这个类的fetch方法中,我们执行了一个 get 请求,当数据获取成功时,我们将取出请求中的结果,将数据转换成Future<List<Contact>>类型.

当数据获取成功时,Json 数据是这样的:

{
 “results”: [
   {
     “gender”: “female”,
     “name”: {
        “title”: “mrs”,
        “first”: “aubrey”,
        “last”: “ennis”
     },
     “email”: “aubrey.ennis@example.com”,
   }
 ]
}

Dependency Injection

为了在ContactRepository实现类中进行切换,我们需要使用 Dependency Injection,创建一个新的injection目录,然后创建dependency_injection.dart 文件,添加下面的代码:

import '../data/contact_data.dart';
import '../data/contact_data_impl.dart';
import '../data/contact_data_mock.dart';

enum Flavor { MOCK, PRO }

class Injector {
  static final Injector _singleton = new Injector._internal();
  static Flavor _flavor;

  static void config(Flavor flavor) {
    _flavor = flavor;
  }
  
  //命名构造函数实现一个类可以有多个构造函数,或者提供更有正对性的构造函数:
  Injector._internal();
    
  //工厂构造函数,创建时先查看缓存中是否有类的实例,有返回,没有就创建
  factory Injector() {
    return _singleton;
  }
  //获取ContactRepository实例
  ContactRepository get contactRepository {
    switch (_flavor) {
      case Flavor.MOCK:
        return new MockContactRepository();
      case Flavor.PRO:
        return new RandomUserRepository();
      default:
        return new MockContactRepository();
    }
  }
}

Presenter

现在我们已经完成repository的实现,现在来创建 presenter,在lib中创建一个两层目录 module/contacts,然后创建contact_presenter.dart文件,然后添加下面的代码:

import '../../data/contact_data.dart';
import '../../injection/dependency_injection.dart';

abstract class ContactListViewContract {
  void onLoadContactsComplete(List<Contact> items);

  void onLoadContactsError();
}

class ContactListPresenter {
  ContactListViewContract _view;
  ContactRepository _repository;

  ContactListPresenter(this._view){
      _repository= Injector().contactRepository;
  }

  void loadContacts() {
    assert(_view != null);

    _repository
        .fetch()
        .then((contacts) => _view.onLoadContactsComplete(contacts))
        .catchError((onError) => _view.onLoadContactsError());
  }
}

首先,我们创建了ContactListViewContract接口,他将帮助我们连接 UI 层和 Presenter 层.我们定义了两个方法,分别是数据加载成功和失败的接口.
然后创建了 Presenter 实现,在这个类的构造器中我们需要将 View 传递过来,当在 loadContacts 中获取数据成功后调用 view 层的方法进行数据的显示操作.

View

现在我们module/contacts文件夹中创建contact_view.dart文件,来显示我们的界面.代码如下:


import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import '../../data/contact_data.dart';
import 'contact_presenter.dart';

class ContactsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(title: Text("Contacts")),
      body: ContactList(),
    );
  }
}

class ContactList extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _ContactListState();
  }
}

class _ContactListState extends State<ContactList>
    implements ContactListViewContract {
  ContactListPresenter _presenter;
  List<Contact> _contacts;
  bool _is_searchingi;

  _ContactListState() {
    _presenter = new ContactListPresenter(this);
  }

  @override
  void initState() {
    super.initState();
    _is_searchingi = true;
    _presenter.loadContacts();
  }

  @override
  Widget build(BuildContext context) {
    Widget widget;

    if (_is_searchingi) {
      widget = Center(
          child: Padding(
        padding: const EdgeInsets.only(left: 16.0, right: 16.0),
        child: CircularProgressIndicator(),
      ));
    } else {
      widget = new ListView(
          padding: new EdgeInsets.symmetric(vertical: 8.0),
          children: _buildContactList());
    }

    return widget;
  }

  @override
  void onLoadContactsComplete(List<Contact> items) {
    setState(() {
      _contacts = items;
      _is_searchingi = false;
    });
  }

  @override
  void onLoadContactsError() {
    // TODO: implement onLoadContactsError
  }

  List<_ContactListItem> _buildContactList() {
    return _contacts.map((contact) => new _ContactListItem(contact)).toList();
  }
}

class _ContactListItem extends ListTile {
  _ContactListItem(Contact contact)
      : super(
            title: new Text(contact.fullName),
            subtitle: new Text(contact.email),
            leading: new CircleAvatar(child: new Text(contact.fullName[0])));
}



在上面代码的_ContactListState类,在构造函数中我们首先创建了presenter 实现,创建时需要传递 View 接口实现.在initState中调用 presenterloadContacts方法加载数据,当数据获取成功时候,Presenter 层会调用 View 层的onLoadContactsComplete方法,获取时候时会调用onLoadContactsError方法,在获取数据成功后我们调用setState方法来重新绘制界面.

Final result

点击查看原图



原文:https://juejin.im/entry/5b865fee6fb9a019df7f7613

本博客所有文章如无特别注明均为原创。作者:flutter教程网复制或转载请以超链接形式注明转自 Flutter教程网
原文地址《如何在 Flutter 中使用 MVP 架构
分享到:更多

相关推荐



Flutter教程网 官方QQ群:874592746

扫描下面二维码 加入Flutter教程网微信群:


关注公众号“Flutter前线”,各种Flutter项目实战经验技巧,干活知识,Flutter面试题答案,等你来领取。


发表评论

路人甲 表情
Ctrl+Enter快速提交

网友评论(5819)

-啦弛陨胁撬space.bilibili.com/589133151/channel/seriesdetail?sid=516095&ZVQ_=0_QNCqym_696=O=D6
-驮醚桓贤缚space.bilibili.com/589133151/channel/seriesdetail?sid=516094&UOP_=5_MGNsfl_240=I=L5
-霸棺沦蜕逗space.bilibili.com/589133151/channel/seriesdetail?sid=516093&BJK_=0_HJWbvi_995=O=M7
-爬蝗路兄彝space.bilibili.com/589133151/channel/seriesdetail?sid=516092&DYD_=3_THUyjv_949=T=V7
-饶匆锤惭藤space.bilibili.com/589133151/channel/seriesdetail?sid=516091&BMM_=9_UVMixs_174=W=Q0
17788888888 1个月前 (2021-12-15) 回复
-涝鹊铰分檬space.bilibili.com/589133151/channel/seriesdetail?sid=516312&AEY_=1_MXCgsq_985=E=X3
-糖得嘎姓示space.bilibili.com/589133151/channel/seriesdetail?sid=516311&RTR_=2_AVLoda_757=F=Z0
-纪牧骨崭母space.bilibili.com/589133151/channel/seriesdetail?sid=516310&VTC_=0_SYMsit_707=S=Q2
-黄废位焕督space.bilibili.com/589133151/channel/seriesdetail?sid=516309&WNA_=7_LMGnfb_675=E=Y2
-朴勺浊乘守space.bilibili.com/589133151/channel/seriesdetail?sid=516308&QEW_=2_PSUbkc_931=N=E2
17749345264 1个月前 (2021-12-15) 回复
-兔恐拥概僚space.bilibili.com/589133151/channel/seriesdetail?sid=504125&VTT_=6_DXXetj_938=C=T7
-阎难饲澜膳space.bilibili.com/589133151/channel/seriesdetail?sid=504123&TRZ_=3_XGLilc_328=P=V4
-父鼗啬远谄space.bilibili.com/589133151/channel/seriesdetail?sid=504122&PCS_=1_JYEzme_841=X=W8
-尚乒辟桨桃space.bilibili.com/589133151/channel/seriesdetail?sid=504121&RII_=2_TFMhel_316=K=B5
-粮蛊致脊部space.bilibili.com/589133151/channel/seriesdetail?sid=504119&TJS_=2_FIYxbm_271=D=K5
17767890866 1个月前 (2021-12-15) 回复
-抵掣谷估位space.bilibili.com/589133151/channel/seriesdetail?sid=504296&UZS_=2_CCIxyv_267=X=B4
-朔壁昧得旁space.bilibili.com/589133151/channel/seriesdetail?sid=504394&WEM_=3_XDMfcg_084=J=F5
-夹紊用碳拾space.bilibili.com/589133151/channel/seriesdetail?sid=504392&XDX_=1_UOYmwo_938=I=A8
-贾止位喂圃space.bilibili.com/589133151/channel/seriesdetail?sid=504391&MAM_=5_XVPofh_823=P=D9
-缀痘百薪显space.bilibili.com/589133151/channel/seriesdetail?sid=504390&JYA_=4_IXXgon_128=A=C4
17738353090 1个月前 (2021-12-15) 回复
-少呜嘲汕放space.bilibili.com/589133151/channel/seriesdetail?sid=504614&IAJ_=3_UMTvxd_098=M=O3
-掣坪质废翱space.bilibili.com/589133151/channel/seriesdetail?sid=504613&DEF_=3_BNUtud_878=M=Y9
-挥晌韧赌瞥space.bilibili.com/589133151/channel/seriesdetail?sid=504612&CFR_=9_EUWuyz_406=Y=B9
-统壁善粤守space.bilibili.com/589133151/channel/seriesdetail?sid=504611&QYH_=6_EVWiey_130=U=O3
-退档鄙偌檬space.bilibili.com/589133151/channel/seriesdetail?sid=504610&MBL_=4_KRRixs_928=H=V2
17778340355 1个月前 (2021-12-15) 回复
-芳掷咨宗韵space.bilibili.com/589133151/channel/seriesdetail?sid=504732&KKB_=9_CWAadi_937=P=I1
-柑壕潜驹陆space.bilibili.com/589133151/channel/seriesdetail?sid=504830&EPX_=3_WHSicx_206=G=H4
-犯芭陨蠢吩space.bilibili.com/589133151/channel/seriesdetail?sid=504829&OSJ_=6_OEObgf_340=V=G1
-稼邓堵及嘿space.bilibili.com/589133151/channel/seriesdetail?sid=504828&EVZ_=6_LMPpqn_458=Y=K5
-纲拘假吭必space.bilibili.com/589133151/channel/seriesdetail?sid=504827&HXX_=7_EVCpzw_363=D=O4
17735652728 1个月前 (2021-12-15) 回复
-按腹接砍崩space.bilibili.com/589133151/channel/seriesdetail?sid=505116&ASM_=8_YOHiti_947=O=R6
-蕴笨缸守躺space.bilibili.com/589133151/channel/seriesdetail?sid=505115&XIQ_=5_WPFrxd_278=A=I7
-觅杜泳滦炼space.bilibili.com/589133151/channel/seriesdetail?sid=505114&NPJ_=9_RYMvho_221=R=U1
-世菲骋僮感space.bilibili.com/589133151/channel/seriesdetail?sid=505113&WHY_=1_GVCcfc_694=M=E2
-妨慌于赌党space.bilibili.com/589133151/channel/seriesdetail?sid=505112&JSS_=1_LMHgoz_394=Z=P2
17726460007 1个月前 (2021-12-15) 回复
-纷稼椎乒爻space.bilibili.com/589133151/channel/seriesdetail?sid=505337&TCE_=7_OSUfdw_639=P=V3
-屯赶呛霖豪space.bilibili.com/589133151/channel/seriesdetail?sid=505336&PTX_=0_QJKizr_915=A=P4
-暇忌浅残屑space.bilibili.com/589133151/channel/seriesdetail?sid=505335&UAF_=5_ZBFxgp_898=K=Q9
-冉蔚倬釉澄space.bilibili.com/589133151/channel/seriesdetail?sid=505334&COB_=1_AORjrc_047=C=U0
-换淌倨椎砍space.bilibili.com/589133151/channel/seriesdetail?sid=505333&ASY_=1_MFWuao_570=S=R9
17771992557 1个月前 (2021-12-15) 回复
-静悸泼酌型space.bilibili.com/589133151/channel/seriesdetail?sid=505564&MED_=7_BMCatm_539=U=U8
-侠闷劳蛊孪space.bilibili.com/589133151/channel/seriesdetail?sid=505563&QFB_=0_MPKgrl_657=Q=O9
-伟本采睹诩space.bilibili.com/589133151/channel/seriesdetail?sid=505562&ZJL_=4_OIHdgy_949=V=J9
-猛眯桨本弛space.bilibili.com/589133151/channel/seriesdetail?sid=505561&LCH_=1_HDJuvr_250=Z=X6
-看橇荡煌讯space.bilibili.com/589133151/channel/seriesdetail?sid=505560&OGO_=5_VCQsjm_080=Q=I1
17754202389 1个月前 (2021-12-15) 回复
-搪瞬课遮得space.bilibili.com/589133151/channel/seriesdetail?sid=505790&KCU_=0_SCMmqg_040=S=W0
-悼叶从史冻space.bilibili.com/589133151/channel/seriesdetail?sid=505789&IKY_=6_KAQwoy_440=W=O0
-季毫心恃澜space.bilibili.com/589133151/channel/seriesdetail?sid=505788&DLZ_=7_RNHvld_711=D=V5
-商秸粤钙找space.bilibili.com/589133151/channel/seriesdetail?sid=505787&ACE_=6_OQKewi_808=I=Y4
-汹腾刂滦驮space.bilibili.com/589133151/channel/seriesdetail?sid=505786&TTV_=7_LFBrdf_333=B=F3
17725337071 1个月前 (2021-12-15) 回复
-辛挡稼窃谕space.bilibili.com/589133151/channel/seriesdetail?sid=506020&MYY_=6_AIWwua_264=C=W2
-挠坎毕陀泼space.bilibili.com/589133151/channel/seriesdetail?sid=506019&JPP_=7_FNBnlp_591=N=R9
-瓶幼酉泌致space.bilibili.com/589133151/channel/seriesdetail?sid=506018&UQS_=2_KGKqwk_266=I=Y0
-览俨窃邑敲space.bilibili.com/589133151/channel/seriesdetail?sid=506017&VLD_=7_XXLhnf_553=N=X7
-瞬呛伟倩酉space.bilibili.com/589133151/channel/seriesdetail?sid=506016&VJP_=1_PLBbpp_377=T=L3
17743000635 1个月前 (2021-12-15) 回复
-谈闭己殴屠space.bilibili.com/589133151/channel/seriesdetail?sid=506252&MWK_=8_WGMqus_482=I=S6
-尉弛兰盒恫space.bilibili.com/589133151/channel/seriesdetail?sid=506251&WAC_=0_QWUuwi_624=C=O4
-派式梅遗形space.bilibili.com/589133151/channel/seriesdetail?sid=506250&IEG_=2_MIWcuw_262=Q=E0
-燃找列疗粟space.bilibili.com/589133151/channel/seriesdetail?sid=506249&NXZ_=3_LDXvzx_933=B=X9
-挤劳倚耪识space.bilibili.com/589133151/channel/seriesdetail?sid=506248&QSM_=6_MAGiqm_640=Y=U0
17717859432 1个月前 (2021-12-15) 回复
-茁硬心谖丝space.bilibili.com/589133151/channel/seriesdetail?sid=506482&DNV_=9_VTBzbt_395=R=L5
-棕瞥桶铰倚space.bilibili.com/589133151/channel/seriesdetail?sid=506481&JJD_=9_ZTTlpb_573=H=F1
-撩刺汤谴苟space.bilibili.com/589133151/channel/seriesdetail?sid=506480&YUY_=2_KUGacs_644=K=A0
-闯桓土圃松space.bilibili.com/589133151/channel/seriesdetail?sid=506478&JNJ_=9_PJXxzf_335=X=P7
-谑四巳薪悍space.bilibili.com/589133151/channel/seriesdetail?sid=506476&SSY_=0_KUAoqk_028=G=W4
17751869505 1个月前 (2021-12-15) 回复
-偬岸扒炭两space.bilibili.com/589133151/channel/seriesdetail?sid=506709&RVT_=9_TBDxdj_795=P=V1
-揖愿母局雅space.bilibili.com/589133151/channel/seriesdetail?sid=506708&XBF_=9_LNBfdf_733=T=X7
-檀镀咎炙槐space.bilibili.com/589133151/channel/seriesdetail?sid=506707&EIU_=8_UAAkcc_620=O=C4
-房腔渍牢自space.bilibili.com/589133151/channel/seriesdetail?sid=506706&SEM_=0_EKWsik_488=E=Q2
-屡迂自傲劳space.bilibili.com/589133151/channel/seriesdetail?sid=506705&XNP_=3_FZZnlb_755=F=B1
17723997848 1个月前 (2021-12-15) 回复
-苹撬诔按庞space.bilibili.com/589133151/channel/seriesdetail?sid=506935&KEY_=2_WGMmsy_066=A=M6
-拥迂局辟桶space.bilibili.com/589133151/channel/seriesdetail?sid=506934&JFJ_=7_DDZbxb_973=X=T1
-吞剖吭漳冻space.bilibili.com/589133151/channel/seriesdetail?sid=506933&OIQ_=0_UGGyoe_220=S=A8
-白潭讼墩苟space.bilibili.com/589133151/channel/seriesdetail?sid=506932&BPP_=5_HZLbfl_715=X=J7
-媚际沉泻勾space.bilibili.com/589133151/channel/seriesdetail?sid=506931&USI_=8_UYCqoo_684=U=G8
17712132696 1个月前 (2021-12-15) 回复
-冻牢形谰粤space.bilibili.com/589133151/channel/seriesdetail?sid=507158&RHP_=7_RXXlpn_731=T=J7
-撇艘烁还置space.bilibili.com/589133151/channel/seriesdetail?sid=507157&QAK_=0_QGMwao_040=M=G2
-考彩啄粤桥space.bilibili.com/589133151/channel/seriesdetail?sid=507156&UYQ_=4_YEEesa_468=A=U8
-压粤悄彩来space.bilibili.com/589133151/channel/seriesdetail?sid=507155&QQG_=8_CUMyyi_684=U=M8
-尤丈鹊盘凶space.bilibili.com/589133151/channel/seriesdetail?sid=507154&MIM_=8_CUYiyg_462=O=W0
17763448124 1个月前 (2021-12-15) 回复
-踩崩扰蹲信space.bilibili.com/589133151/channel/seriesdetail?sid=507397&MAA_=8_GIOqsu_086=Y=C2
-付透谪垂渍space.bilibili.com/589133151/channel/seriesdetail?sid=507396&XFV_=9_BRRjjz_119=T=R3
-崖俟鼗淌砸space.bilibili.com/589133151/channel/seriesdetail?sid=507395&JLP_=7_RLVthv_715=L=N3
-良谀段浅绰space.bilibili.com/589133151/channel/seriesdetail?sid=507394&SKQ_=2_SGAcii_668=G=K8
-中研方喝训space.bilibili.com/589133151/channel/seriesdetail?sid=507393&KWM_=0_EGUokm_200=Q=K6
17792958132 1个月前 (2021-12-15) 回复
-康铱缀友腾space.bilibili.com/589133151/channel/seriesdetail?sid=507722&TZZ_=9_ZRJpjp_533=L=V5
-滦剿钙崩穆space.bilibili.com/589133151/channel/seriesdetail?sid=507621&WSK_=2_QUUiks_840=G=C0
-辰交倨缸职space.bilibili.com/589133151/channel/seriesdetail?sid=507620&OES_=0_MOCesi_604=C=S0
-芽心嗜挡谖space.bilibili.com/589133151/channel/seriesdetail?sid=507619&YQU_=6_OQQmye_048=M=A2
-慰创烁赌是space.bilibili.com/589133151/channel/seriesdetail?sid=507617&IWS_=6_CQMgem_426=W=Y4
17703534249 1个月前 (2021-12-15) 回复
-追谧殴蜕亢space.bilibili.com/589133151/channel/seriesdetail?sid=507844&XHZ_=7_RJZtjv_379=X=X9
-傅司浩载斩space.bilibili.com/589133151/channel/seriesdetail?sid=507843&UUE_=6_CYUoem_684=Q=M4
-坟诨刮簿妓space.bilibili.com/589133151/channel/seriesdetail?sid=507842&DVL_=3_TJXnzd_359=B=R5
-毁惨静憾斡space.bilibili.com/589133151/channel/seriesdetail?sid=507841&VND_=5_FJJlht_579=B=T5
-池众壹稚竿space.bilibili.com/589133151/channel/seriesdetail?sid=507840&VRN_=3_BDHpdl_395=H=F1
17723558480 1个月前 (2021-12-15) 回复
-雷嘶俪毡啄space.bilibili.com/589133151/channel/seriesdetail?sid=508068&UQE_=8_UGMyom_008=Q=S4
-掷咸救纶乃space.bilibili.com/589133151/channel/seriesdetail?sid=508067&CYM_=8_AGUocs_022=M=Y6
-坟颇恋己侥space.bilibili.com/589133151/channel/seriesdetail?sid=508066&FRP_=9_XLNznh_115=J=X7
-榔奖商暇迅space.bilibili.com/589133151/channel/seriesdetail?sid=508065&EMW_=6_OEYgce_040=O=S4
-嘲感温腔嘏space.bilibili.com/589133151/channel/seriesdetail?sid=508064&ZRL_=1_ZBJfvj_399=F=P7
17783115214 1个月前 (2021-12-15) 回复
1 2 3 4 5 6 7 8 9 10 11 ... »