前言
看了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<T>(context, listen: true) 或者去掉e.markNeedsNotifyDependents() ,我都不会说这话。。。
- Bloc框架做了一些让我十分纳闷的操作,_startListening办法中的回调中调用了 e.markNeedsNotifyDependents() ,齐全没用!因为没应用Provider.of<T>(context, listen: true) 向 InheritedElement 增加子Element,所以是刷新了个寂寞!为了验证我的想法,我debug了 framework层的notifyClients办法,调用emit或yield刷新的时候, _dependents的map始终为空,哎。。。
- 摈弃了Provider机制极简的Callback回调机制,抉择了Stream流这种。。。
我下面吐槽了很多,并非我对bloc有什么意见
- Bloc我也用了较长的工夫,深度应用过程,对其用法做了一些优化,还为其写了一个代码生成插件,为它也算付出了一些工夫和精力
- 然而:代码是不会说谎的,所有好的或不好的都在其中,用心体悟就能感触到。
如果我了解有误,恳请大家指出,我真的很想找出点其中所蕴含的深意,扭转我下面的想法。。。
为啥说情绪简单呢?
之前在看Provider源码的时候,看的有些头痛,外部逻辑的确有些简单,然而总流程理通,刷新逻辑清晰之后,那是一种酣畅淋漓的感觉!苦楚之后便是一种微小的满足感,并对Provider纯熟使用Framework层各种api,而后实现了精彩的刷新机制,感到赞叹!
而后,下面也讲了,我在Bloc下面的确花了一些精力,优化它的应用,而后看了他的源码,再想想之前看的Provider源码,忽然有种微小的落差感。
在我看来,这样赫赫有名的开源库,下面这点疙瘩齐全能够防止;兴许是这种莫名的高期待,让我产生了这种落差。。。
应用
这边介绍下应用,对官网的用法做了一些调整
调整心路的历程,可参照:flutter_bloc应用解析---骚年,你还在手搭bloc吗!
上面就间接写出调整后写法了
插件
因为官网插件生成的写法,和调整后写法差距有点大,而且官网插件不反对生成view层和相干设置,此处我就撸了一个插件,欠缺了相干性能
请留神,Wrap代码和提醒代码片段,参靠了官网插件规定
Wrap Widget 规定来着:intellij_generator_plugin
快捷代码生成规定来着: intellij_generator_plugin
- 在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应用解析---骚年,你还在手搭bloc吗!
前置常识
想弄懂Bloc原理,须要先理解下Stream的相干常识
StreamController、StreamBuilder:这俩者的搭配也能够轻松的实现刷新部分Widget,来看下应用
- view:Stream流必须要有敞开的操作,此处就须要应用StatefulWidget,须要它的dispose回调
class StreamPage extends StatefulWidget { const StreamPage({Key? key}) : super(key: key); @override _StreamPageState createState() => _StreamPageState();}class _StreamPageState extends State<StreamPage> { final logic = StreamLogic(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Bloc-Bloc范例')), body: Center( child: StreamBuilder<StreamState>( initialData: logic.state, stream: logic.stream, builder: (context, snapshot) { return Text( '点击了 ${snapshot.data!.count} 次', style: TextStyle(fontSize: 30.0), ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () => logic.increment(), child: Icon(Icons.add), ), ); } @override void dispose() { logic.dispose(); super.dispose(); }}
- logic:Stream数据源是泛型,能够间接应用根底类型,此处应用实体,是为了前期可扩大更多数据
class StreamLogic { final state = StreamState(); // 实例化流控制器 final _controller = StreamController<StreamState>.broadcast(); Stream<StreamState> get stream => _controller.stream; void increment() { _controller.add(state..count = ++state.count); } void dispose() { // 敞开流控制器,开释资源 _controller.close(); }}
- state
class StreamState { int count = 0;}
- 效果图
实际上,看了上述的应用,会发现有几个很麻烦的中央
- 须要创立Stream的一系列对象
- Stream流必须要有敞开操作,所以要应用StatefulWidget
- StreamBuilder须要写三个参数,很麻烦
Bloc作者借住Provider的InheritedProvider控件,将下面的痛点都解决了
刷新机制
Bloc的刷新机制很简略,下面的Stream操作,根本说明了其外围的刷新机制,然而Bloc作者做了一些封装,咱们来看看
BlocProvider的魅力
BlocProvider是一个十分重要的控件,刷新参数的精简和Stream流的敞开都和其无关,因为该封装了一个Provider外面InheritedProvider;然而,然而在我看来,他仍旧是一个很有魅力的控件
- BlocProvider:BlocProvider的源码很简略,上面就是这个类的源码
class BlocProvider<T extends BlocBase<Object?>> extends SingleChildStatelessWidget with BlocProviderSingleChildWidget { /// {@macro bloc_provider} BlocProvider({ Key? key, required Create<T> create, this.child, this.lazy, }) : _create = create, _value = null, super(key: key, child: child); BlocProvider.value({ Key? key, required T value, this.child, }) : _value = value, _create = null, lazy = null, super(key: key, child: child); /// Widget which will have access to the [Bloc] or [Cubit]. final Widget? child; final bool? lazy; final Create<T>? _create; final T? _value; static T of<T extends BlocBase<Object?>>( BuildContext context, { bool listen = false, }) { try { return Provider.of<T>(context, listen: listen); } on ProviderNotFoundException catch (e) { if (e.valueType != T) rethrow; throw FlutterError( ''' BlocProvider.of() called with a context that does not contain a $T. No ancestor could be found starting from the context that was passed to BlocProvider.of<$T>(). This can happen if the context you used comes from a widget above the BlocProvider. The context used was: $context ''', ); } } @override Widget buildWithChild(BuildContext context, Widget? child) { final value = _value; return value != null ? InheritedProvider<T>.value( value: value, startListening: _startListening, lazy: lazy, child: child, ) : InheritedProvider<T>( create: _create, dispose: (_, bloc) => bloc.close(), startListening: _startListening, child: child, lazy: lazy, ); } static VoidCallback _startListening( InheritedContext<BlocBase> e, BlocBase value, ) { final subscription = value.stream.listen( (dynamic _) => e.markNeedsNotifyDependents(), ); return subscription.cancel; }}
BlocProvider和BlocProvider.value的区别
看下面源码可知:BlocProvider.value没有做Stream主动敞开操作
- 所以BlocProvider.value不应该在一般的单页面应用,可用于全局Bloc实例
- 单页面Bloc请应用BlocProvider去创立Bloc或Cubit
create是内部实例化的XxxBloc,最终传入了InheritedProvider中
- create就是内部传入的XxxBloc实例
该实例间接传入了InheritedProvider中,这就是波及到Provider中,最终是贮存在 _InheritedProviderScopeElement中, _startListening也是Provider的内容
- 这外部的原理是比较复杂且很重要的,感兴趣请查看:源码篇:Flutter Provider的另一面(万字图文+插件)
说真的 _startListening外面的逻辑没什么卵用
- markNeedsNotifyDependents这个api是Provider作者专门为Provider子Element刷新做的,必须配套 Provider.of<T>(context, listen: true) 去注册Widget控件才行
- 波及逻辑太多,都在下面Provider源码分析文章中,感兴趣的能够去看看
BlocProvider.of<T>
- 作用:能够在BlocProvider包裹的子控件中,获取到BlocProvider Create传入的XxxBloc
- 请留神:如果应用BlocProvider父布局context是拿不到XxxBloc的,必须是BlocProvider的子布局
原理:源码篇:Flutter Provider的另一面(万字图文+插件),还是在这篇文章里
- 我真的不是推广这文章啊,BlocProvider这部分,Bloc用了太多Provider个性
- Provider文章,我花了九牛二虎之力将原理分析完,在此处,就没必要再做复读机了
总结:来演绎下BlocProvider这个类的作用
- BlocProvider或会贮存内部传入的XxxBloc实例,XxxBloc类必须继承BlocBase
- BlocProvider存储的XxxBloc实例,能够通过BlocProvider.of<T>获取到(必须是在BlocProvider或其子Widget)
- BlocProvider获取的实例XxxBloc可能主动开释;BlocProvider.value命名构造函数实例的XxxBloc不会主动开释
BlocProvider实现了下面这三个碉堡的性能,根本就能够把Stream应用模式彻底精简了
- 图示
基石BlocBase
毋庸置疑,BlocBase是很重要的一个抽象类
- BlocBase
abstract class BlocBase<State> { BlocBase(this._state) { Bloc.observer.onCreate(this); } StreamController<State>? __stateController; StreamController<State> get _stateController { return __stateController ??= StreamController<State>.broadcast(); } State _state; bool _emitted = false; State get state => _state; Stream<State> get stream => _stateController.stream; @Deprecated( 'Use stream.listen instead. Will be removed in v8.0.0', ) StreamSubscription<State> listen( void Function(State)? onData, { Function? onError, void Function()? onDone, bool? cancelOnError, }) { return stream.listen( onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError, ); } void emit(State state) { if (_stateController.isClosed) return; if (state == _state && _emitted) return; onChange(Change<State>(currentState: this.state, nextState: state)); _state = state; _stateController.add(_state); _emitted = true; } @mustCallSuper void onChange(Change<State> change) { Bloc.observer.onChange(this, change); } @mustCallSuper void addError(Object error, [StackTrace? stackTrace]) { onError(error, stackTrace ?? StackTrace.current); } @protected @mustCallSuper void onError(Object error, StackTrace stackTrace) { Bloc.observer.onError(this, error, stackTrace); assert(() { throw BlocUnhandledErrorException(this, error, stackTrace); }()); } @mustCallSuper Future<void> close() async { Bloc.observer.onClose(this); await _stateController.close(); }}
下面的BlocBase做了几件比拟重要的事,来梳理下
Bloc.observer这个不重要,这是框架外部定义的一个类,这边能够疏忽掉,不太重要
贮存了传入的state对象
- 每次应用emit刷新的时候,会将传入state替换之前存储state对象
- emit做了一个判断,如果传入state和存储state对象雷同,将不执行刷新操作(这就是我在State类外面,加clone办法的起因)
- 初始化了Stream一系列对象
- 封装了敞开Stream流的操作
- 将下面的代码精简下
abstract class BlocBase<T> { BlocBase(this.state) : _stateController = StreamController<T>.broadcast(); final StreamController<T> _stateController; T state; bool _emitted = false; Stream<T> get stream => _stateController.stream; void emit(T newState) { if (_stateController.isClosed) return; if (state == newState && _emitted) return; state = newState; _stateController.add(state); _emitted = true; } @mustCallSuper Future<void> close() async { await _stateController.close(); }}
BlocBuilder
BlocBuilder对StreamBuilder的用法做了很多精简,来看下外部实现
BlocBuilder
- 此处须要关注下builder参数; buildWhen是个判断是否须要更新的参数
- build办法外面调用了builder,须要看下父类BlocBuilderBase
typedef BlocWidgetBuilder<S> = Widget Function(BuildContext context, S state);class BlocBuilder<B extends BlocBase<S>, S> extends BlocBuilderBase<B, S> { const BlocBuilder({ Key? key, required this.builder, B? bloc, BlocBuilderCondition<S>? buildWhen, }) : super(key: key, bloc: bloc, buildWhen: buildWhen); final BlocWidgetBuilder<S> builder; @override Widget build(BuildContext context, S state) => builder(context, state);}
BlocBuilderBase
- context.read< B>() 和 Provider.of<T>(this, listen: false)成果是一样的,就是对后者的一个封装
- 此处通过context.read< B>() 拿到了 咱们在 BlocProvider中传入的XxxBloc对象,赋值给了_BlocBuilderBaseState中的 _bloc变量
- BlocBuilderBase形象了一个build办法,在 _BlocBuilderBaseState中赋值给了 BlocListener
- BlocBuilderBase还没法看出刷新逻辑,几个重要的参数:_bloc,listener,widget.build都传给了BlocListener;须要看下BlocListener的实现
abstract class BlocBuilderBase<B extends BlocBase<S>, S> extends StatefulWidget { const BlocBuilderBase({Key? key, this.bloc, this.buildWhen}) : super(key: key); final B? bloc; final BlocBuilderCondition<S>? buildWhen; Widget build(BuildContext context, S state); @override State<BlocBuilderBase<B, S>> createState() => _BlocBuilderBaseState<B, S>();}class _BlocBuilderBaseState<B extends BlocBase<S>, S> extends State<BlocBuilderBase<B, S>> { late B _bloc; late S _state; @override void initState() { super.initState(); _bloc = widget.bloc ?? context.read<B>(); _state = _bloc.state; } ... @override Widget build(BuildContext context) { ... return BlocListener<B, S>( bloc: _bloc, listenWhen: widget.buildWhen, listener: (context, state) => setState(() => _state = state), child: widget.build(context, _state), ); }}
- BlocListener:参数传给父类的构造函数了,须要看下父类BlocListenerBase的实现
class BlocListener<B extends BlocBase<S>, S> extends BlocListenerBase<B, S> const BlocListener({ Key? key, required BlocWidgetListener<S> listener, B? bloc, BlocListenerCondition<S>? listenWhen, Widget? child, }) : super( key: key, child: child, listener: listener, bloc: bloc, listenWhen: listenWhen, );}
- BlocListenerBase:精简了一些逻辑代码
abstract class BlocListenerBase<B extends BlocBase<S>, S> extends SingleChildStatefulWidget { const BlocListenerBase({ Key? key, required this.listener, this.bloc, this.child, this.listenWhen, }) : super(key: key, child: child); final Widget? child; final B? bloc; final BlocWidgetListener<S> listener; final BlocListenerCondition<S>? listenWhen; @override SingleChildState<BlocListenerBase<B, S>> createState() => _BlocListenerBaseState<B, S>();}class _BlocListenerBaseState<B extends BlocBase<S>, S> extends SingleChildState<BlocListenerBase<B, S>> { StreamSubscription<S>? _subscription; late B _bloc; late S _previousState; @override void initState() { super.initState(); _bloc = widget.bloc ?? context.read<B>(); _previousState = _bloc.state; _subscribe(); } ... @override Widget buildWithChild(BuildContext context, Widget? child) { return child!; } @override void dispose() { _unsubscribe(); super.dispose(); } void _subscribe() { _subscription = _bloc.stream.listen((state) { if (widget.listenWhen?.call(_previousState, state) ?? true) { widget.listener(context, state); } _previousState = state; }); } void _unsubscribe() { _subscription?.cancel(); _subscription = null; }}
终于找了要害的代码了!
能够发现Bloc是通过 StreamController 和 listen配合实现刷新的
调用的 widget.listener(context, state),这个实现的办法是个setState,大家能够看看 _BlocBuilderBaseState这个类
_bloc.stream.listen( (state) { if (widget.listenWhen?.call(_previousState, state) ?? true) { widget.listener(context, state); } _previousState = state; },);
精简BlocBuild
下面的BlocBuild的实现逻辑还是太绕,封装层级太多,上面写个精简版的BlocBuild
当然了,必定会保留BlocBuild刷新的外围逻辑
class BlocEasyBuilder<T extends BlocBase<V>, V> extends StatefulWidget { const BlocEasyBuilder({ Key? key, required this.builder, }) : super(key: key); final Function(BuildContext context, V state) builder; @override _BlocEasyBuilderState createState() => _BlocEasyBuilderState<T, V>();}class _BlocEasyBuilderState<T extends BlocBase<V>, V> extends State<BlocEasyBuilder<T, V>> { late T _bloc; late V _state; StreamSubscription<V>? _listen; @override void initState() { _bloc = BlocProvider.of<T>(context); _state = _bloc.state; //数据扭转刷新Widget _listen = _bloc.stream.listen((event) { setState(() {}); }); super.initState(); } @override Widget build(BuildContext context) { return widget.builder(context, _state); } @override void dispose() { _listen?.cancel(); super.dispose(); }}
- 来看下效果图:具体的应用代码,请查看:flutter_use
Event机制
如果应用Bloc模式开发,会多出一个Event层,该层是定义所有的事件交互
这边提一下
- Bloc:省略了一些代码
abstract class Bloc<Event, State> extends BlocBase<State> { /// {@macro bloc} Bloc(State initialState) : super(initialState) { _bindEventsToStates(); } StreamSubscription<Transition<Event, State>>? _transitionSubscription; StreamController<Event>? __eventController; StreamController<Event> get _eventController { return __eventController ??= StreamController<Event>.broadcast(); } void add(Event event) { if (_eventController.isClosed) return; try { onEvent(event); _eventController.add(event); } catch (error, stackTrace) { onError(error, stackTrace); } } Stream<Transition<Event, State>> transformEvents( Stream<Event> events, TransitionFunction<Event, State> transitionFn, ) { return events.asyncExpand(transitionFn); } @protected @visibleForTesting @override void emit(State state) => super.emit(state); Stream<State> mapEventToState(Event event); Stream<Transition<Event, State>> transformTransitions( Stream<Transition<Event, State>> transitions, ) { return transitions; } @override @mustCallSuper Future<void> close() async { await _eventController.close(); await _transitionSubscription?.cancel(); return super.close(); } void _bindEventsToStates() { _transitionSubscription = transformTransitions( transformEvents( _eventController.stream, (event) => mapEventToState(event).map( (nextState) => Transition( currentState: state, event: event, nextState: nextState, ), ), ), ).listen( (transition) { if (transition.nextState == state && _emitted) return; try { emit(transition.nextState); } catch (error, stackTrace) { onError(error, stackTrace); } }, onError: onError, ); }}
整体逻辑比拟清晰,来理一下
Bloc是抽象类
- 构造函数外面调用 _bindEventsToStates() 办法
- Bloc形象了一个mapEventToState(Event event)办法,继承Bloc抽象类,必须实现该办法
Bloc类中,实例了Stream流对象,来做Event的事件触发机制
- 增加Event事件时,会触发 _bindEventsToStates() 办法中的listener回调
_bindEventsToStates外面做了一些操作
- 被增加的Event事件:events.asyncExpand(transitionFn);先将本身Event参数传入transitionFn办法中执行
- transitionFn的逻辑是:将Event参数传入mapEventToState中,而后mapEventToState回传State对象
- 而后触发listen回调,listen中,将state传emit中,而后触发刷新控件重建
总结
下面几个要害的类剖析完,整个Bloc的运行机制,一下子就清朗了
BlocProvider
- 负责贮存 传入XxxBloc加以贮存
- 提供的of办法,能够在BlocProvider或其子节点地位,获取到贮存的XxxBloc
- 提供回收资源的回调(回收Stream流)
BlocBase
- 贮存了传入的state对象
- 初始化了Stream一系列对象
- 封装了敞开Stream流的操作
BlocBuilder
- 实质是StatefulWidget
- 通过BlocProvider获取到XxxBloc,再通过其listener办法监听数据扭转
数据扭转后,通过setState重建StatefulWidget,以达到部分刷新的成果
# 手搓一个状态治理框架
Bloc的原理绝对Provider而言,要简略很多。。。
模拟Bloc的刷新机制,来手搓一个状态治理框架!用EasyC来命名吧!
手搓
- EasyC:首先须要写一个基类,解决Stream一系列的操作
abstract class EasyC<T> { EasyC(this.state) : _controller = StreamController<T>.broadcast(); final StreamController<T> _controller; T state; bool _emitted = false; Stream<T> get stream => _controller.stream; void emit(T newState) { if (_controller.isClosed) return; if (state == newState && _emitted) return; state = newState; _controller.add(state); _emitted = true; } @mustCallSuper Future<void> close() async { await _controller.close(); }}
EasyCProvider
- 这里就不应用Provider框架提供的InheritedProvider了
- 这边我用InheritedWidget手搓了一个
- of办法和stream流的敞开都搞定了;不必手动关流,也不必写StatefulWidget了!
class EasyCProvider<T extends EasyC> extends InheritedWidget { EasyCProvider({ Key? key, Widget? child, required this.create, }) : super(key: key, child: child ?? Container()); final T Function(BuildContext context) create; @override bool updateShouldNotify(InheritedWidget oldWidget) => false; @override InheritedElement createElement() => EasyCInheritedElement(this); static T of<T extends EasyC>(BuildContext context) { var inheritedElement = context.getElementForInheritedWidgetOfExactType<EasyCProvider<T>>() as EasyCInheritedElement<T>?; if (inheritedElement == null) { throw 'not found'; } return inheritedElement.value; }}class EasyCInheritedElement<T extends EasyC> extends InheritedElement { EasyCInheritedElement(EasyCProvider<T> widget) : super(widget); bool _firstBuild = true; late T _value; T get value => _value; @override void performRebuild() { if (_firstBuild) { _firstBuild = false; _value = (widget as EasyCProvider<T>).create(this); } super.performRebuild(); } @override void unmount() { _value.close(); super.unmount(); }}
- EasyCBuilder:最初整一个定点刷新Widget
class EasyCBuilder<T extends EasyC<V>, V> extends StatefulWidget { const EasyCBuilder({ Key? key, required this.builder, }) : super(key: key); final Function(BuildContext context, V state) builder; @override _EasyCBuilderState createState() => _EasyCBuilderState<T, V>();}class _EasyCBuilderState<T extends EasyC<V>, V> extends State<EasyCBuilder<T, V>> { late T _easyC; late V _state; StreamSubscription<V>? _listen; @override void initState() { _easyC = EasyCProvider.of<T>(context); _state = _easyC.state; //数据扭转刷新Widget _listen = _easyC.stream.listen((event) { setState(() {}); }); super.initState(); } @override Widget build(BuildContext context) { return widget.builder(context, _state); } @override void dispose() { _listen?.cancel(); super.dispose(); }}
下面这三个文件,根本就把Bloc的刷新机制再现了
同时,也去掉了我心中的一个疙瘩,Bloc源码对 Provider的 _startListening办法,莫名其妙的应用。。。
应用
应用根本和Bloc一摸一样
我原本想把emit俩个新旧state对象比照的判断去掉,然而想想Bloc作者对这个理念如同有很深的执念,在很多中央都做了解决;所以,这边我也就保留了,也能够保留Bloc原汁原味的用法
- view
class CounterEasyCPage extends StatelessWidget { final easyC = CounterEasyC(); @override Widget build(BuildContext context) { return EasyCProvider( create: (BuildContext context) => easyC, child: Scaffold( appBar: AppBar(title: Text('自定义状态治理框架-EasyC范例')), body: Center( child: EasyCBuilder<CounterEasyC, CounterEasyCState>( builder: (context, state) { return Text( '点击了 ${easyC.state.count} 次', style: TextStyle(fontSize: 30.0), ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () => easyC.increment(), child: Icon(Icons.add), ), ), ); }}
- logic
class CounterEasyC extends EasyC<CounterEasyCState> { CounterEasyC() : super(CounterEasyCState().init()); ///自增 void increment() => emit(state.clone()..count = ++state.count);}
- state
class CounterEasyCState { late int count; CounterEasyCState init() { return CounterEasyCState()..count = 0; } CounterEasyCState clone() { return CounterEasyCState()..count = count; }}
- 效果图
全局也是能够的,和Provider没什么不一样,我这边就不反复写了
总结
这手搓的EasyC框架,保留Bloc刷新机制的精华,同时,也做了大量的精简
置信有缘人只有用心看看,肯定可能了解的
Bloc的源码并不简单,他是对Stream的应用,做了一个大大的精简,根本应用痛点,全都封装起来,外部解决了
最初
留言板
Provider和Bloc的源码解析终于写完了,就差最初一篇GetX了。。。
为了证实我写的剖析源码是有作用且有成果的,在开端,我都依据其状态治理框架的刷新机制,手搓了一个全新的状态治理框架
抉择状态治理框架,应该是一件比拟谨慎的事;当时能够先看看其原理,了解了他的外部运行机制,就齐全能够去按需抉择了,因为你明确了它的外部运行机制,就算应用过程中呈现什么问题,你也能从容应对了;如果你怕作者弃坑或不称心其性能,抉择你本人想要的刷新机制,本人去手搓一个!
Provider,Bloc,GetX这三个框架,我都写了相应插件,如果你抉择的状态治理框架是这个三者中任意一个,置信这些插件,都能帮你实现一些反复的工作量
相干地址
- 文章中Demo的Github地址:flutter_use
Web成果:https://cnad666.github.io/flu...
- 如果相干性能按钮没看到,可能须要你清下浏览器缓存
Windows:Windows平台安装包
- 明码:xdd666
系列文章
- 源码篇:Flutter Provider的另一面(万字图文+插件)
- 源码篇:Handler那些事(万字图文)
- 源码篇:ThreadLocal的奇思妙想(万字图文)