源码篇:Flutter Bloc背后的思想,这是一篇写的“艰难”的文章

Posted 清风Coolbreeze

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了源码篇:Flutter Bloc背后的思想,这是一篇写的“艰难”的文章相关的知识,希望对你有一定的参考价值。

前言

看了Bloc源码后,心情有点复杂呀。。。

说点积极的...

用过Bloc的靓仔们,肯定能感受到,Bloc框架对开发页面,做了很清晰划分,框架强行定了俩种开发模式

  • Bloc模式:该模式划分四层结构
    • bloc:逻辑层
    • state:数据层
    • event:所有的交互事件
    • view:页面
  • Cubit模式:该模式划分了三层结构
    • cubit:逻辑层
    • state:数据层
    • view:页面

作者在层次的划分上还是很老道的,state层是直接写死在框架内部,这层必须要单独分出来;我感觉如果不是被大型项目的克苏鲁代码山坑过,应该不会有这么深的执念

这个state层加的,我觉得相当有必要,因为某个页面一旦维护的状态很多,将状态变量和逻辑方法混在一起,后期维护会非常头痛。

说点批判的...

  • 大家可能在群里,经常看到一些老哥说:Bloc是将Provider封装了一层。

    • 这里我证实下:这是真的,Bloc确实将Provider封了一层
    • 但是仅仅只用到Provider中子节点查询最近父节点InheritedElement数据和顶层Widget并列布局功能,Provider最经典的刷新机制,完全没用到!
  • 我相当怀疑Bloc作者没看懂Provider的刷新机制

    • 哪怕bloc框架在build widget里用到了一行: Provider.of(context, listen: true) 或者去掉e.markNeedsNotifyDependents() ,我都不会说这话。。。
    • Bloc框架做了一些让我非常疑惑的操作,_startListening方法中的回调中调用了 e.markNeedsNotifyDependents() ,完全没用!因为没使用Provider.of(context, listen: true) 向 InheritedElement 添加子Element,所以是刷新了个寂寞!为了验证我的想法,我debug了 framework层的notifyClients方法,调用emit或yield刷新的时候, _dependents的map一直为空,哎。。。
  • 抛弃了Provider机制极简的Callback回调机制,选择了Stream流这种。。。

  • 我上面吐槽了很多,并非我对bloc有什么意见

    • Bloc我也用了较长的时间,深度使用过程,对其用法做了一些优化,还为其写了一个代码生成插件,为它也算付出了一些时间和精力
    • 但是:代码是不会说谎的,所有好的或不好的都在其中,用心体悟就能感受到。

如果我理解有误,恳请大家指出,我真的很想找出点其中所蕴含的深意,改变我上面的想法。。。

为啥说心情复杂呢?

之前在看Provider源码的时候,看的有些头痛,内部逻辑确实有些复杂,但是总流程理通,刷新逻辑清晰之后,那是一种酣畅淋漓的感觉!痛苦之后便是一种巨大的满足感,并对Provider熟练运用Framework层各种api,然后实现了精彩的刷新机制,感到赞叹!

然后,上面也讲了,我在Bloc上面确实花了一些精力,优化它的使用,然后看了他的源码,再想想之前看的Provider源码,突然有种巨大的落差感。

在我看来,这样大名鼎鼎的开源库,上面这点疙瘩完全可以避免;也许是这种莫名的高期待,让我产生了这种落差。。。

使用

这边介绍下使用,对官方的用法做了一些调整

下面就直接写出调整后写法了

插件

因为官方插件生成的写法,和调整后写法差距有点大,而且官方插件不支持生成view层和相关设置,此处我就撸了一个插件,完善了相关功能

请注意,Wrap代码和提示代码片段,参靠了官方插件规则

  • android Studio里面搜索 flutter bloc

  • 生成模板代码

  • 支持修改后缀

  • Wrap Widget (alt + enter):RepositoryProvider,BlocConsumer,BlocBuilder,BlocProvider,BlocListener

  • 输入 bloc 可生成快捷代码片段

用法

插件可生成俩种模式代码:Bloc和Cubit;来看下

Cubit模式

  • view
class CounterPage extends StatelessWidget {
  final cubit = CounterCubit();

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (BuildContext context) => cubit,
      child: Container(),
    );
  }
}
  • cubit
class CounterCubit extends Cubit<CounterState> {
  CounterCubit() : super(CounterState().init());
}
  • state
class CounterState {
  CounterState init() {
    return CounterState();
  }

  CounterState clone() {
    return CounterState();
  }
}

Bloc模式

  • view:默认添加了一个初始化事件
class CounterPage extends StatelessWidget {
  final bloc = CounterBloc();

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (BuildContext context) => bloc..add(InitEvent()),
      child: Container(),
    );
  }
}
  • bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterState().init());

  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    if (event is InitEvent) {
      yield await init();
    }
  }

  Future<CounterState> init() async {
    return state.clone();
  }
}
  • event
abstract class CounterEvent {}

class InitEvent extends CounterEvent {}
  • state
class CounterState {
  CounterState init() {
    return CounterState();
  }

  CounterState clone() {
    return CounterState();
  }
}

总结

Bloc和Cubit模式对于结构,划分的很清楚,因为有多层结构划分,务必会有相应的模板代码和文件,没有插件的帮助,每次都写这些模板代码,会非常难受;这边为大家写了这个插件,如果有什么BUG,麻烦及时反馈哈。。。

以上是关于源码篇:Flutter Bloc背后的思想,这是一篇写的“艰难”的文章的主要内容,如果未能解决你的问题,请参考以下文章

详解底层源码:Flutter Bloc背后的思想

详解底层源码:Flutter Bloc背后的思想

Flutter Bloc源码分析

Flutter 研发阶段性总结 基本设计模式BLoC

Flutter 研发阶段性总结 基本设计模式BLoC

Flutter - flutter_bloc状态管理