Bloc

作者: shz_Minato | 来源:发表于2020-01-24 17:39 被阅读0次

    Bloc

    Bloc:Business Logic Component,该库的目的:将表现层和逻辑层分离,并且让状态更加可以 预料。那么如何让状态 变得可以预料呢?首先,当状态有了 改变时,为这种改变作出某些 调整。其次,收缩状态改变的入口,只有一种方法 可以让状态 发生变化。

    Bloc的核心概念

    假设我们有一个计数器的应用,该应用有两个按钮:+、-按钮,分别用来加一和减一。

    Events----事件

    事件是Bloc的输入。

    事件的来源有:用户的交互、页面的生命周期等。这些都可以产生事件。

    比如:用户点击了加一或者减一按钮,那么我们需要把 某些事情 通知给应用中枢,应用中枢来响应 用户的点击(输入)。 这个点击 就是 事件产生的地方。 某些事情就是 我们定义的事件。

    enum CounterEvent { increment, decrement }
    

    在这里我们使用枚举定义了两个事件,可能在某些其他需要携带 额外信息的场景中,我们需要使用class

    States----状态

    状态是bloc的输出,表现 我们应用某一部分的状态。UI组件可以根据当前的状态全部或者部分的重绘。

    我们在上面定义了加一和减一事件:CounterEvent.increment、CounterEvent.decrement。 现在我们需要表现出应用的状态,由于我们是计数器应用,所以应用的状态非常简单----数值,表现当前应用的数字是什么。

    Transitions----转场

    转场就是 一个状态到另一个状态的 改变,类似于我们动画的差值器过度。它由当前状态、事件、下一个状态组成。

    比如:当用户点击加一或者减一按钮了,会触发CounterEvent事件,这些事件会 更新应用的状态(数值)。那么一个状态的改变 就是 一个转场。

    下面就是 一个加一按钮事件的 转场

    {
      "currentState": 0,
      "event": "CounterEvent.increment",
      "nextState": 1
    }
    

    Streams----流

    Dart中流的概念:一个异步数据的序列。下面我们看一下Java中流的概念:一个支持 串行和并行 操作的 元素序列,是不是很像。

    Bloc是基于RxDart的,但是抽象了所有的Rx的特定实现细节。

    流可以看成是一个水管,异步数据就是 水。流的相关概念可以在这里看

    首先我们创建一个数据流:

    Stream<int> countStream(int max) async* {
        for (int i = 0; i < max; i++) {
            yield i;
        }
    }
    //流中元素为 0---max的int值
    

    然后我们可以将流中数据求和:

    Future<int> sumStream(Stream<int> stream) async {
        int sum = 0;
        await for (int value in stream) {
            sum += value;
        }
        return sum;
    }
    
    

    最后我们可以看一下流的使用方式:

    void main() async {
        /// Initialize a stream of integers 0-9
        Stream<int> stream = countStream(10);
        /// Compute the sum of the stream of integers
        int sum = await sumStream(stream);
        /// Print the sum
        print(sum); // 45
    }
    
    

    Blocs----Business Logic Component

    Bloc是一个组件:将一个事件的输入流 转为 一个状态的输出流。所谓的转就是:bloc将一个流 转换 为另一个流。旧的流中元素是 事件,新的流中的元素是状态。

    我们自定义的Bloc需要继承自核心包中的Bloc。比如:

    import 'package:bloc/bloc.dart';
    
    //接受两个范型:输入流的元素类型、输出流的元素类型
    class CounterBloc extends Bloc<CounterEvent, int> {
    
    }
    
    

    初次之外,每一个Bloc都有一个初始的状态。初始状态就是 任何事件 未发生之前的 状态。比如 我们可以将我们的计数器的 初始状态 设置为 0.

    class CounterBloc extends Bloc<CounterEvent, int> {
      @override
      int get initialState => 0;
    }
    

    并且,Bloc的作用是 将一个流 转为 另一个流,因为需要我们指定转换的方法。这个转换的方法就是父类抽象的mapEventToState方法。参数的范型就是输入流的类型,返回值的范型就是输出流的类型。 这里我们需要指定接收到 加一 和 减一类型时,输出流的元素应该是什么。

    class CounterBloc extends Bloc<CounterEvent, int> {
      @override
      int get initialState => 0;
    
      @override
      Stream<int> mapEventToState(CounterEvent event) async* {
        switch (event) {
          case CounterEvent.decrement:
            //减一   -----》状态流的元素为 当前状态-1
            yield state - 1;
            break;
          case CounterEvent.increment:
            //加一 ----》状态流的元素为 当前状态+1
            yield state + 1;
        }
      }
    }
    

    以上就是我们一个完成的Bloc,根据事件流的元素 去 生成状态流的元素。那么我们需要:如何告诉Bloc事件产生了呢?

    Bloc基类中有一个add方法,该方法的作用就是:发送事件并触发mapEventToState。因此:我们需要在事件产生的地方 调用该方法,并把事件发送出去。比如:用户交互的地方,Bloc内部等。

    现在我们手动调用add方法:

    void main() {
        //声明bloc
        CounterBloc bloc = CounterBloc();
    
        for (int i = 0; i < 3; i++) {
            //模拟事件产生 并添加
            bloc.add(CounterEvent.increment);
        }
    }
    
    

    我们并没有看到什么输出,因为我们并没有做任何事情。我们可以重写onTransition方法,去追踪转场过程。

    class CounterBloc extends Bloc<CounterEvent, int> {
      @override
      int get initialState => 0;
    
      @override
      Stream<int> mapEventToState(CounterEvent event) async* {
        switch (event) {
          case CounterEvent.decrement:
            yield state - 1;
            break;
          case CounterEvent.increment:
            yield state + 1;
        }
      }
    
      @override
      void onTransition(Transition<CounterEvent, int> transition) {
        // TODO: implement onTransition
        super.onTransition(transition);
        print(transition);
      }
    }
    

    在执行后我们可以发现:

    打印了
    Transition { currentState: 0, event: CounterEvent.increment, nextState: 1 }
    Transition { currentState: 1, event: CounterEvent.increment, nextState: 2 }
    Transition { currentState: 2, event: CounterEvent.increment, nextState: 3 }
    

    每一个转场包括了:当前的状态、本次事件、下个状态。

    总结

    以上就是Bloc的一些核心的概念,Bloc的基础还是流,它所做的事情就是转换:事件 map to 状态。

    相关文章

      网友评论

          本文标题:Bloc

          本文链接:https://www.haomeiwen.com/subject/odocthtx.html