FlutterBloc 2.1.1迁移至6.0.6

  1. 依赖于Bloc Package升级(2.0.0->6.1.0)

  2. Provider扁平化依赖通过nested实现

  3. initialState属性删除,主要是为了兼容懒加载(巨坑,由于之前工程在初始化需要进行缓存及逻辑计算,导致初始化函数机构混乱,再加上受限于先于flutter独特的初始化方法,没办法通过this直接引用原方法,所以针对这点还需要尽量减少initialState的逻辑)

  4. 语法糖变更,Provider.of的方式可以直接通过context.read/context.watch来实现

  5. 新增BlocConsumer,加强了对bloc流事件传递流程步骤,进一步细化,基于BlocBuilder语法糖

Bloc变更

  1. StateSubject & EventSubject移除,通过StreamController来管理EventState
  2. 通过BlocObserver替代BlocDelegate,完善了Bloc生命周期监听
  3. 引入Cubit基类,将State大部分逻辑抽屉,Bloc作为其子类更注重Event事件的管理

Bloc类关系图

  • 6.1.0

  • 2.0.0

BlocBuilderBase

  • 相比之前的版本主要是将state的监听转移到BlocListener中执行,对职责划分进行了优化
  • 关系图
DiagnosticableTree (diagnostics.dart)
    Widget (framework.dart)
        StatefulWidget (framework.dart)
            BlocBuilderBase (bloc_builder.dart)
                BlocBuilder (bloc_builder.dart)
  • 实现
class _BlocBuilderBaseState<C extends Cubit<S>, S>
    extends State<BlocBuilderBase<C, S>> {
  C _cubit;
  S _state;

  @override
  void initState() {
    super.initState();
    /// 1.初始化默认会设置cubit(bloc)和state
    _cubit = widget.cubit ?? context.bloc<C>();
    _state = _cubit.state;
  }

  @override
  void didUpdateWidget(BlocBuilderBase<C, S> oldWidget) { ...
  ///2. cubit(bloc)更新检测,从新赋值
  }

  @override
  Widget build(BuildContext context) {
  ///3. 通过listener来监听state变更,调用`setState`更新widget
    return BlocListener<C, S>(
      cubit: _cubit,
      ///4. 通过用户自定义`listenWhen`和`build`实现页面按条件更新
      listenWhen: widget.buildWhen,
      listener: (context, state) => setState(() => _state = state),
      child: widget.build(context, _state),
    );
  }
}

BlocListenerBase

  • 继承链变更SingleChildStatefulWidget,主要是为了方便Nested对嵌套Widget进行扁平化压缩,其它无变化
  • 管理bloc的state流事件订阅和释放
  • 关系图
DiagnosticableTree (diagnostics.dart)
    Widget (framework.dart)
        StatefulWidget (framework.dart)
            SingleChildStatefulWidget (nested.dart)
                BlocListenerBase (bloc_listener.dart)
                    BlocListener (bloc_listener.dart)
  • 实现
class _BlocListenerBaseState<C extends Cubit<S>, S>
    extends SingleChildState<BlocListenerBase<C, S>> { ...
  @override
  void initState() { ...
    _subscribe();
  }

  @override
  void didUpdateWidget(BlocListenerBase<C, S> oldWidget) { ..
        _unsubscribe(); ...
      _subscribe(); ...

  @override
  void dispose() {
    _unsubscribe(); ... 

BlocConsumer

  • 扩展了State的监听流程
  • 关系
DiagnosticableTree (diagnostics.dart)
    Widget (framework.dart)
        StatelessWidget (framework.dart)
            BlocConsumer (bloc_consumer.dart)

  • 实现
class BlocConsumer<C extends Cubit<S>, S> extends StatelessWidget {
  /// 1. 初始化条件设定, 增加对listener和build的前置条件过滤
  const BlocConsumer({
    Key key,
    @required this.builder,
    @required this.listener,
    this.cubit,
    this.buildWhen,
    this.listenWhen,
  })   ...
  
  /// 2. 对blocBuilder进行默认的包装,算是一个语法糖吧
  @override
  Widget build(BuildContext context) {
    final cubit = this.cubit ?? context.bloc<C>();
    return BlocBuilder<C, S>(
      cubit: cubit,
      builder: builder,
      buildWhen: (previous, current) {
        if (listenWhen?.call(previous, current) ?? true) {
          listener(context, current);
        }
        return buildWhen?.call(previous, current) ?? true;
      },
    );
  }
}
  • 使用
/// BlocConsumer<BlocA, BlocAState>(
///   listenWhen: (previous, current) {
///     // return true/false to determine whether or not
///     // to invoke listener with state
///   },
///   listener: (context, state) {
///     // do stuff here based on BlocA's state
///   },
///   buildWhen: (previous, current) {
///     // return true/false to determine whether or not
///     // to rebuild the widget with state
///   },
///   builder: (context, state) {
///     // return widget here based on BlocA's state
///   }
/// )

BlocProvider

  • 继承链变更
DiagnosticableTree (diagnostics.dart)
    Widget (framework.dart)
        StatelessWidget (framework.dart)
            SingleChildStatelessWidget (nested.dart)
                BlocProvider (bloc_provider.dart)
  • 实现-初始化
///1. 通过Value创建,销毁时不会自动释放
  BlocProvider.value({
    Key key,
    @required T value,
    Widget child,
  }) : this._(
          key: key,
          create: (_) => value,
          child: child,
        );
///2. 通过create方式创建,销毁时会释放bloc
  @override
  Widget buildWithChild(BuildContext context, Widget child) {
    return InheritedProvider<T>(
      create: _create,
      dispose: _dispose,
      child: child,
      lazy: lazy,
    );
  }
  • 构建用户界面配置信息
  @override
  Widget buildWithChild(BuildContext context, Widget child) {
    return InheritedProvider<T>(
      create: _create,   //提供传入的value(cubit/bloc)
      dispose: _dispose, //可选,通过value初始化时则为null
      child: child,      //用户定义的child包装
      lazy: lazy,        //决定create是否懒加载,及用到时初始化
    );
  }

MultiProvider

  • 扁平化多个Provider,基于Nested实现
DiagnosticableTree (diagnostics.dart)
    Widget (framework.dart)
        StatelessWidget (framework.dart)
            Nested (nested.dart)
                MultiProvider (provider.dart)
                    MultiBlocListener (multi_bloc_listener.dart)
                    MultiBlocProvider (multi_bloc_provider.dart)
                    MultiRepositoryProvider (multi_repository_provider.dart)

Provider

DiagnosticableTree (diagnostics.dart)
    Widget (framework.dart)
        StatelessWidget (framework.dart)
            SingleChildStatelessWidget (nested.dart)
                InheritedProvider (provider.dart)
                    Provider (provider.dart)
                        RepositoryProvider (repository_provider.dart)

小结

  • Flutter Bloc升级整体风险可空,initialState修改工作量大,代码结构上会有一些冲突,可采用静态方法替换实例先适配initialState.
  • Provider基于Nested进行了重新包装,它原来所依赖的ValueDelegate系列的类被移除,目前仅Navigator有采用次类进行包裹,PageNavigator的语法糖失效,需要进行适配,可先临时通过globalKey访问。

TODO:

  • Provider,Nested与PageNavigator适配

Flutter Bloc相关依赖

1.Hive, 它是一款轻量级的快速的基于键值存储的库,
- 日志型的kv模型,不支持随机写入,类似日志文件追加操作,Bitcask将随机写入转化为顺序写入,实现原理
- 在任意时刻系统太难过中一哟0u一个数据文件支持写入(active data file),其余文件为只读(order data file),所有的写操作都是针最后一个文件进行追加.
- 除了增加外,删除和更新也全部不随机读写已有文件。删除只是增加一个带删除标志的记录,随后更新索引hash;而更新也是一样。
- 启动Bitcask时,它会将所有数据的位置信息全部读入一个内存中的哈希表,也就是索引文件;线索文件(hint file)
- 参考连接:(https://cloud.tencent.com/developer/article/1083737)[https://cloud.tencent.com/developer/article/1083737]

  1. HydrateBloc
    • 新增加密功能,默认使用AES256 CBC with PKCS7 padding
    • 子类重写父类HydrateBlocstatic Future<HydratedStorage> build方法可以适配
    • Storage的改造,原来是通过BlocDelegate来持有Storage进行数据读写,现在需要哦通过HydratedBlocMixin来持有Storage进行数据读写
      • 6.0.6 版本HydratedBloc
原文地址:https://www.cnblogs.com/wwoo/p/flutterbloc-211qian-yi-zhi606.html