一、Bloc 介绍

Bloc 的名字比较新颖,这个状态管理框架的目的是将 UI 层和业务逻辑进行分离。Bloc 的复杂度处于 ScopedModel 和 Redux 之间,相较于 ScopedModel,Bloc 拥有分明的架构处于业务逻辑,相较于 Redux,Bloc 着重于业务逻辑的分解,使得整个框架对于开发来讲简单实用。

二、Bloc 的层次结构

Bloc 分为三层:

  • Data Layer(数据层),用于提供数据。
  • Bloc(Business Logic) Layer(业务层),通过继续 Bloc 类实现,用于处理业务逻辑。
  • Presentation Layer(表现层),用于 UI 构建。

Presentation Layer 只与 Bloc Layer 交互,Data Laye 也只与 Bloc Layer 交互。Bloc Layer 作为重要一层,处于表现层和数据层之间,使得 UI 和数据通过 Bloc Layer 进行交互。

由此可见,Bloc 的架构和客户端主流的 MVC 和 MVP 架构比较相似,但也存在 Event 和 State 的概念一同构成响应式框架。

三、Bloc 需要知道的概念

BlocProvider,通常做为 App 的根布局。BlocProvider 可以保存 Bloc,在其它页面通过BlocProvider.of<Bloc>(context)获取 Bloc。

Event,用户操作 UI 后发出的事件,用于通知 Bloc 层事件发生。

State,页面状态,可用于构建 UI。通常是 Bloc 将接收到的 Event 转化为 State。

Bloc 架构的核心是 Bloc 类,Bloc 类是一个抽象类,有一个 mapEventToState(event)方法需要实现。mapEventToState(event)顾名思义,就是将用户点击 View 时发出的 event 转化为构建 UI 所用的 State。另外,在 StatefulWidget 中使用 bloc 的话,在 widget dispose 时,要调用 bloc.dispose()方法进行释放。

四、Bloc 的实践

这里以常见的获取列表选择列表为例子。一个页面用于展示选中项和跳转到列表,一个页面用于显示列表。

  1. 引入 Redux 的第三方库

pubspec.yaml 文件中引入 flutter_bloc 第三方库支持 bloc 功能。

  # 引入 bloc 第三方库flutter_bloc: ^0.9.0
复制代码
  1. 使用 Bloc 插件

这一步可有可无,但使用插件会方便开发,不使用的话也没什么问题。

Bloc 官方提供了 VSCode 和 Android studio 的插件,方便生成 Bloc 框架用到的相关类。 下文以 Android studio 的插件为例。

比如 list 页面,该插件会生成相应的类

从生成的五个文件中也可以看到,list_bloc 负责承载业务逻辑,list_page 负责编写 UI 界面,list_eventlist_state 分别是事件和状态,其中 list.dart 文件是用于导出前面四个文件的。

具体使用可见

Android studio 的 Bloc 插件

VSCode 的 Bloc 插件

  1. 使用 BlocProvider 作为根布局

main.dart 中,使用 BlocProvider 作为父布局包裹,用于传递需要的 bloc。Demo 中包含两个页面,一个是展示页面 ShowPage,一个是列表页面 ListPage。

上面讲到,Bloc 的核心功能在于 Bloc 类,对于展示页面 ShowPage,会有一个 ShowBloc 继续自 Bloc 类。由于展示页面 ShowPage 会和列表页面 ListPage 有数据的互动,所以这里将 ShowBloc 保存在 BlocProvider 中进行传递。

@overrideWidget build(BuildContext context) {return BlocProvider(bloc: _showBloc,child: MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),home: ShowPage()));}
复制代码
  1. 展示页面 ShowPage

① ShowEvent

列表的 item 点击后,需要发送一个 event 通知其它页面列表被选中,这里定义一个 SelectShowEvent 作为这种 event 通知。

class SelectShowEvent extends ShowEvent {String selected;SelectShowEvent(this.selected);
}
复制代码

② ShowState

State 用于表示一种界面状态,即一个 State 就对应一个界面。插件在一开始会生成一个默认状态,InitialShowState。我们可以使用 InitialShowState 来代表初始的界面。另外,我们自己定义一种状态,SelectedShowState,代表选中列表后的 State。

@immutable
abstract class ShowState {}class InitialShowState extends ShowState {}class SelectedShowState extends ShowState {String _selectedString = "";String get selected => _selectedString;SelectedShowState(this._selectedString);
}复制代码

③ ShowBloc

Bloc 的主要职责是接收 Event,然后把 Event 转化为对应的 State。这里的 ShowBloc 继续自 Bloc,需要重写实现抽象方法 mapEventToState(event)。在这个方法中,我们判断传过来的 event 是不是 SelectShowEvent,是则拿到 SelectShowEvent 中的 selected 变量去构建 SelectedShowState。mapEventToState(event)返回的是一个 Stream,我们通过 yield 关键字去返回一个 SelectedShowState。

class ShowBloc extends Bloc<ShowEvent, ShowState> {@overrideShowState get initialState => InitialShowState();@overrideStream<ShowState> mapEventToState(ShowEvent event,) async* {if (event is SelectShowEvent) {yield SelectedShowState(event.selected);}}
}
复制代码

④ ShowPage

在 ShowPage 的界面上,我们需要根据 showBloc 中是否有被选中的列表项目去展于页面,所以这里我们先使用使用BlocProvider.of<ShowBloc>(context)去拿到 showBloc,接着再用 BlocBuilder 根据 showBloc 构建界面。使用 BlocBuilder 的好处就是可以让页面自动响应 showBloc 的变化而变化。

var showBloc = BlocProvider.of<ShowBloc>(context);
...
BlocBuilder(bloc: showBloc,builder: (context, state) {if (state is SelectedShowState) {return Text(state.selected);}return Text("");}),
复制代码
  1. 列表页面 ListPage

① ListEvent

列表页面,我们一开始需要从网络中拉取列表数据,所以定义一个 FetchListEvent 事件在进入页面时通知 ListBloc 去获取列表。

@immutable
abstract class ListEvent extends Equatable {ListEvent([List props = const []]) : super(props);
}class FetchListEvent extends ListEvent {}
复制代码

② ListState

InitialListState 是插件默认生成的初始状态,另外定义一个 FetchListState 代表获取列表完成的状态。

@immutable
abstract class ListState extends Equatable {ListState([List props = const []]) : super(props);
}class InitialListState extends ListState {}class FetchListState extends ListState {List<String> _list = [];UnmodifiableListView<String> get list => UnmodifiableListView(_list);FetchListState(this._list);
}
复制代码

③ ListBloc

在 ListBloc 中,进行从网络获取列表数据的业务。这里通过一个延时操作摸拟网络请求,最后用 yield 返回列表数据。

class ListBloc extends Bloc<ListEvent, ListState> {@overrideListState get initialState => InitialListState();@overrideStream<ListState> mapEventToState(ListEvent event,) async* {if (event is FetchListEvent) {// 模拟网络请求await Future.delayed(Duration(milliseconds: 2000));var list = ["1. Bloc artitechture","2. Bloc artitechture","3. Bloc artitechture","4. Bloc artitechture","5. Bloc artitechture","6. Bloc artitechture","7. Bloc artitechture","8. Bloc artitechture","9. Bloc artitechture","10. Bloc artitechture"];yield FetchListState(list);}}
}复制代码

④ ListPage

在列表页面初始化时有两个操作,一个是初始化 listBloc,一个是发出列表请求的 Event。

  @overridevoid initState() {bloc = ListBloc(); // 初始化listBlocbloc.dispatch(FetchListEvent()); // 发出列表请求事件super.initState();}
复制代码

接下用,便是用 BlocBuilder 去响应状态。当 state 是 InitialListState,说明未获取列表,则显示 loading 界面,当 state 是 FetchListState 时,说明已经成功获取列表,显示列表界面。

body: BlocBuilder(bloc: bloc,builder: (context, state) {// 根据状态显示界面if (state is InitialListState) {// 显示 loading 界面return buildLoad();} else if (state is FetchListState) {// 显示列表界面var list = state.list;return buildList(list);}}));
复制代码

最后,记得对 bloc 进行 dispose()

  @overridevoid dispose() {bloc.dispose();super.dispose();}
复制代码

具体代码可以到 github 查看。

总结

在 Bloc 的架构中,将一个页面和一个 Bloc 相结合,由页面产生 Event,Bloc 根据业务需要将 Event 转化为 State,再把 State 交给页面中的 BlocBuilder 构建 UI。Demo 中只是给出了简单的状态管理,实际项目中,比如网络请求,有请求中、请求成功、请求失败的多种状态,可以做适当封装使 Bloc 更加易用。相比于 Redux,Bloc 不需要将所有状态集中管理,这样对于不同模块的页面易于拆分,对于代码量比较大的客户端而言,Bloc 的架构会相对比较友好。

转载于:https://juejin.im/post/5ca5c603f265da30a3303d00

Flutter状态管理学习手册(三)——Bloc相关推荐

  1. FlyAI小课堂:Flutter 状态管理之BLoC

    在正式介绍 BLoC之前, 为什么我们需要状态管理.如果你已经对此十分清楚,那么建议直接跳过这一节. 如果我们的应用足够简单,Flutter 作为一个声明式框架,你或许只需要将 数据 映射成 视图 就 ...

  2. Flutter 状态管理之Bloc上

    前言:Flutter 的状态管理插件有很多,比如 Provider,GetX 还有本篇要讲述的 Bloc .Bloc 目前最新的版本是 flutter_bloc: ^8.0.1. BLoC 依赖 St ...

  3. Flutter 状态管理指南之 Provider

    2019 Google I/O 大会,Flutter 团队在"Pragmatic State Management in Flutter "演讲上正式介绍了 Provider.自此 ...

  4. flutter 状态管理 flutter_bloc 的使用以及总结

    Bloc介绍 flutter_bloc 8.0,直接把mapEventToState方法去掉,需要手动注册事件处理器,不用再写if else 来判断event ,也不用写yield flutter_b ...

  5. Flutter状态管理1-ChangeNotifierProvider的使用

    关于Flutter中的状态管理,可以参考官网的介绍:Simple app state management 中文网的介绍:简单的应用状态管理 Flutter 官方的两个sample: provider ...

  6. Flutter 状态管理

    目录 一.状态管理简介 1.1 为什么需要状态管理 1.1.1 Flutter与adr/ios UI框架区别 1.1.2 状态管理框架使用场景 1.2 需要解决的问题 二.状态管理框架现有方案调研 2 ...

  7. uni-app store 状态管理学习,多写几遍就会了

    uni-app使用了一段时间了,一直没有用到store 状态管理,还是应该学习一下,以后会用到的 1.使用hbuiderx创建uni-app项目 2.与static同级创建store文件夹,store ...

  8. Flutter 状态管理之Bloc下

    这篇是使用 Bloc 来实现业务逻辑与UI分离.主要就是慕课网课程列表的网络请求并且展示. 首先定义一个基础事件的类,如下: abstract class LessonEvent {} 然后我定义了3 ...

  9. 【flutter-mobx】Flutter 状态管理- 使用 MobX实现计数器

    实践flutter mobx: 提示:对下面这篇掘金文章的实践,通过flutter结合 mobx 实现计数器,过程中也添加了一些处理和注释,代码放在feat/mobx下 https://juejin. ...

  10. SpringMVC学习手册(三)------EL和JSTL(上)

    1.含义 EL:       Expression Language , 表达式语言 JSTL:   Java Server Pages Standard Tag Library, JSP标准标签库  ...

最新文章

  1. linux ssh Unused,ssh免密码登录 - leopardlinux的个人空间 - OSCHINA - 中文开源技术交流社区...
  2. CTFshow php特性 web135
  3. 面试奇葩——交换两变量值的一些邪门歪道
  4. android 构造xml,android 中生成xml文件
  5. scala 方法、函数定义小结
  6. Codeforces Gym - 100917 部分题解
  7. mysql limit 越大越慢_mysql 优化之14:php mysql limit 分页优化,页面值越大查询越慢...
  8. 分布式选举协议:Paxos
  9. 我可以获得标记为--assume-unchanged的文件列表吗?
  10. 【Computer Organization笔记28】总复习
  11. Windows程序设计学习-API-SetBkMode
  12. Node:项目文件使用async报错var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _calle
  13. 时间管理工具推荐,助你实现高效能,慢生活
  14. python绘制动态数字时钟_用 Python 画动态时钟
  15. # 冰冻三尺非一日之寒。
  16. 负载均衡(Load Balance)介绍
  17. lua之诡异的tonumber
  18. codeforces1146G Zoning Restrictions
  19. 找工作经验——EE Master 找CS工作总结
  20. 嵌入式硬件构件与底层驱动构件基本规范

热门文章

  1. atitit 信息化概论导论原理 艾提拉著.docx 目录 1. 第1章 计算工具及其进步 1 2. 第3章 计算机程序与软件开发 2 3. 第5章 通信与计算机网络 2 4. 第7章 信息的概念 2
  2. Atitit 数据结构与常见文件元数据结构 目录 1. 分类 内部数据结构与外部存储数据结构 1 2. 编程语言内部数据结构 (堆栈 树 图等 1 2.1. 数据结构 (集合,列表,tree,map
  3. Atitit 常见每日流程日程日常工作.docx v9 每次pertime Atitit 常见每日每天流程日程日常工作 v9 raf attilax总结分享.docx Ver history i
  4. Atitit.guice3 ioc 最佳实践 o9o
  5. paip.c++ 开发 api 手册文档总结
  6. paip.提升用户体验-----可访问性大原则及一些方法
  7. SSH: scp 拉取云端文件到本地端
  8. 中国证券IT发展简史(上)
  9. django使用mysql函数_请问django 可以操作mysql函数么?
  10. crt 生成pem_如何将.pem转换为.crt和.key?