源码篇:Flutter Bloc背后的思想,一篇纠结的文章 (6)

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), ), ), ); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwsxyx.html