美文网首页Android
flutter: 解析 Bloc 实现原理

flutter: 解析 Bloc 实现原理

作者: 李小轰 | 来源:发表于2021-08-31 16:35 被阅读0次

    序言

    flutter开发中,我们使用 bloc 框架,基于状态变更进行响应式开发。本篇文章,小轰将 bloc 核心业务块进行拆解简化,聊一聊它的实现思想,bloc 核心能力分为如下两点:

    • 添加事件 event,将 '事件流' 转换为 '状态流' state
    • 监听 bloc 流,每次 state 状态变更,通知 widget 更新

    1. 事件流 > 状态流 (中转)

    首先,我们将bloc代码简化,我们来看看bloc如何将事件流转换为状态流。简化代码如下:

    import 'dart:async';
    abstract class ACubit<State> {
      StreamController<State> _controller = StreamController<State>.broadcast();
      State _state;
      State get state => _state;
    
      ACubit(this._state);
    
      ///发送State状态到流里面
      void emit(State state) {
        if (_controller.isClosed) return;
        if (state == _state) return;
        _state = state;
        _controller.add(_state);
      }
    
      ///提供方法外部监听State
      StreamSubscription<State> listen(
        void Function(State state) onData, {
        Function onError,
        void Function() onDone,
        bool cancelOnError,
      }) {
        return _controller.stream.listen(
          onData,
          onError: onError,
          onDone: onDone,
          cancelOnError: cancelOnError,
        );
      }
    
      Future<void> close() {
        return _controller.close();
      }
    }
    

    ACubit提供最基础的能力。提供listen方法给外部监听 'State' 变更;emit方法用来响应state状态变更。

    abstract class ABloc<Event, State> extends ACubit<State> {
      final _eventController = StreamController<Event>.broadcast();
    
      ABloc(State initState) : super(initState) {
        _bindEventToState();
      }
    
      ///发送事件
      void add(Event event) {
        if (_eventController.isClosed) return;
        _eventController.add(event);
      }
    
      ///需上层实现 (根据event转成state)
      Stream<State> mapEventToState(Event event);
    
      ///将事件流(event)转换成状态流(state)
      _bindEventToState() {
        _eventController.stream
            // asyncExpand 将流内容进行类型转换,结果还是流
            .asyncExpand((event) => mapEventToState(event))
            .listen((nextState) {
          ///将nextState与当前state进行比对,比对成功后放入流中
          emit(nextState);
        });
      }
    }
    

    ABloc 是我们直接使用的基类。在构造函数中调用了_bindEventToState将事件流转换为状态流。

    2. 使用 BlocBuilder 实时监听状态变更, 如何实现的呢?

    小轰做了一个简化版的原理讲解:

    import 'package:flutter/material.dart';
    import 'a_bloc.dart';
    
    class BlocBuilder<T extends ACubit<S>, S> extends StatefulWidget {
      final T cubit;
      final Widget Function(BuildContext context, S state) builder;
    
      const BlocBuilder({
        Key key,
        @required this.cubit,
        @required this.builder,
      }) : super(key: key);
    
      @override
      _BlocBuilderState<S> createState() => _BlocBuilderState<S>();
    }
    
    class _BlocBuilderState<S> extends State<BlocBuilder> {
      void _update() {
        setState(() {});
      }
    
      @override
      void initState() {
        ///监听state状态变更
        widget.cubit?.listen((_) {
          _update();
        });
        super.initState();
      }
    
      @override
      void dispose() {
        widget.cubit?.close();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context){
        return widget.builder(
          context,
          widget.cubit.state,
        );
      }
    }
    

    封装 BlocBuilder

    • 构造函数中传入自定义的 bloc (继承ABloc),builder 传参用于获取每次 state 变更通知。
    • initState初始化方法中对cubit进行状态监听,每次状态变更直接调用setState方法进行页面更新

    调用示例如下:

    return BlocBuilder<CountBloc, CountState>(
          cubit: CountBloc(CountState(1)),
          builder: (context, state) {
           return Container(...省略业务代码)
          },
        )
    

    总结

    bloc 库中引用了provider 等三方库。基于InheritedWidget实现了数据共享能力。本篇文章,小轰只为演示Bloc核心的处理思想。详细请查阅Bloc源码。


    扩展

    InheritedProvider 实现数据共享
    Bloc同时add两次只响应一次问题处理

    相关文章

      网友评论

        本文标题:flutter: 解析 Bloc 实现原理

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