前言

官方Github地址:https://felangel.github.io/bloc/#/
在理解BLoC之前,最好先对 Stream 有基础了解。

Bloc的目的是将展示层与逻辑层拆分开,使flutter代码层次更清晰,易于测试和复用。

参考

架构

Bloc的设计秉承了三个核心价值:

  • 简洁
  • 强大
  • 可测试

image.png

数据层(Data Layer)

数据层用于从一个或多个数据源获取或操作数据,数据层可以被分为两部分:

  • Data Provider
  • Repository

这一层,是应用的最底层,负责数据库交互、网络请求和其他的异步数据源操作。

Data Provider

Data Provider负责提供原始数据(raw data)。数据提供层通常会暴露简单的API执行CRUD操作。

  1. class DataProvider {
  2. Future<RawData> readData() async {
  3. // Read from DB or make network request etc...
  4. }
  5. }

Repository

Repository层是一个或多个Data Provider与Bloc层交互的包裹器。

  1. class Repository {
  2. final DataProviderA dataProviderA;
  3. final DataProviderB dataProviderB;
  4. Future<Data> getAllDataThatMeetsRequirements() async {
  5. final RawDataA dataSetA = await dataProviderA.readData();
  6. final RawDataB dataSetB = await dataProviderB.readData();
  7. final Data filteredData = _filterData(dataSetA, dataSetB);
  8. return filteredData;
  9. }
  10. }

如上面代码所示,repository layer可以与多个data providers交互,并在将结果提交给Business Logic层之前对数据进行转换。

逻辑层(Bloc Layer)

Bloc层主要职责是根据展示层输入的events反馈新的state。可以把Bloc层想象为一个介于UI层(Presentation Layer)和数据层之间的桥梁。bloc层获取由用户输入产生的evnets并与repository交互并生成新的,可以被展示层消费的新的state。

  1. class BusinessLogicComponent extends Bloc {
  2. final Repository repository;
  3. Stream mapEventToState(event) async* {
  4. if (event is AppStarted) {
  5. yield await repository.getAllDataThatMeetsRequirements();
  6. }
  7. }
  8. }

逻辑层之间的通讯

Every bloc has a state stream which other blocs can subscribe to in order to react to changes within the bloc.

Blocs 可以依赖其他的 blocs 来响应自身状态的改变。

  1. class MyBloc extends Bloc {
  2. final OtherBloc otherBloc;
  3. StreamSubscription otherBlocSubscription;
  4. MyBloc(this.otherBloc) {
  5. otherBlocSubscription = otherBloc.state.listen((state) {
  6. // React to state changes here.
  7. // Dispatch events here to trigger changes in MyBloc.
  8. });
  9. }
  10. @override
  11. void dispose() {
  12. otherBlocSubscription.cancel();
  13. super.dispose();
  14. }
  15. }

展示层(Presentation Layer)

展示层负责根据bloc的状态渲染自身,同时,它也负责管理用户的输入及应用对应event的生命周期。

  1. class PresentationComponent {
  2. final Bloc bloc;
  3. PresentationComponent() {
  4. bloc.dispatch(AppStarted());
  5. }
  6. build() {
  7. // render UI based on bloc state
  8. }
  9. }

核心理念

Events(事件)

Events are the input to a Bloc. They are commonly dispatched in response to user interactions such as button presses or lifecycle events like page loads.

事件是BLoC的输入,他们通常被(例如:button点击、页面加载这样的)用户操作所触发。

States(状态)

States are the output of a Bloc and represent a part of your application’s state. UI components can be notified of states and redraw portions of themselves based on the current state.

Transitions(转变)

当从一个状态(state)变成另外一种状态的这种改变称为Transition。一个Transition包含三部分:

  • 当前状态 (current state)
  • 触发状态改变的事件 (event)
  • 下一个状态 (next state)

Streams(流)

Stream代表一系列的异步数据。

A stream is a sequence of asynchronous data.

Blocs(业务逻辑组件)

每个Bloc必须继承至bloc package的基础 Bloc 类。

  1. import 'package:bloc/bloc.dart';
  2. class CounterBloc extends Bloc<CounterEvent, int> {
  3. // add codes here ...
  4. @override
  5. int get initialState => 0;
  6. @override
  7. Stream<int> mapEventToState(CounterEvent event) async* {
  8. switch (event) {
  9. case CounterEvent.decrement:
  10. yield currentState - 1;
  11. break;
  12. case CounterEvent.increment:
  13. yield currentState + 1;
  14. break;
  15. }
  16. }
  17. }
  • 每个Bloc必须定义一个初始 state。
  • 每个Bloc必须实现基类的 mapEventToState 函数,这个函数将event作为输入的参数,且必须返回一个Stream类型的新的state。
  • 可以在任何时机通过currentState属性访问当前的bloc state值。
  • 每个Bloc(Business Logic Component)都有dispatch 方法,该方法通过event触发执行 mapEventToState函数。

    onTransition

    通过复写 onTransition 方法,可以在Bolc的state发生改变之前获取状态信息。

    Tip: onTransition is a great place to add bloc-specific logging/analytics

onError

通过复写 onError 方法,可以获取Bloc中产生的异常。

Tip: onError is a great place to add bloc-specific error handling.

BlocDelegate(Bloc委托)

使用Bloc的另外一个附带好处是,可以在同一个地方访问所有的 Transitions。如果希望响应所有的Transitions,可以创建一个BlocDelegate。
image.png

Flutter BLoC

BlocBuilder

BlocBuilder 是一个实现了 Bolcbuilder 函数的 Flutter widget。BlocBuilder 与 StreamBuilder 很相似,但其拥有更为简洁的API,减少了大量模版代码的编写。

BlocProvider

BlocProvider 是能够通过 BlocProvider.of<T>(context) 向子组件提供bloc 的Flutter widget。BlocProvider 被当作注入组件使用。因此,单例的bloc可以被多个子组件共享。

MultiBlocProvider

BlocListener

MultiBlocListener