再用经典的Flutter计数器示例介绍BLoC。
阅读了一些有关反应式编程的文章,并在应用程序中使用了BLoC模式,我意识到自己并没有赶上什么。 和往常一样,没有足够的时间来完成所有事情,但是现在有了一个免费的小时,就变得有力量-我决定用BLoC模式编写最简单的Flutter应用程序。
在cat animashka应用程序和解释下,我为什么要这样写。 社区的意见非常有趣。

是的,我们已经多次写过关于这种模式的文章,但是无论如何,没有使用它的明确说明和规则,而且经常出现如何正确地在应用程序中实现逻辑的问题。
本文的目的是使我自己以及我希望对读者有所了解。
因此,正如Google工程师所说的那样,模式的定义-BLOC是一个简单的类,其中:
- 所有输出流
- 所有输入都是流
- 此类应从可视界面中删除逻辑
要实现此模式,我们可以在必要时使用rxdart库,但我们可以不使用它。
这不会消除您可能认为的反应性。 当包的创建者自己编写时,rxdart在使用流时将功能添加到Dart语言已经内置的丰富功能中。
应用程式

因此,我们将应用程序与带有计数器的应用程序一起使用,该计数器在创建项目时自动创建,并尝试使用BLoC模式重写它。
任务:
- 从小部件中删除所有逻辑
- 在BLoC类中,仅接收输入流,仅输出输出流。 例如, 文章评论中建议的功能。

它不适合我们,因为它违反了仅将流传递给类的规则。
解决方案:
- 我们从小部件中删除了所有逻辑。 我们制作无状态类,并停止使用setState更新状态。
- 我们使用内置的小部件来显示仪表读数的不同位置,该小部件专门用于显示流中的数据-StreamBuilder。
class MyHomePage extends StatelessWidget { CounterBloc counterBloc = CounterBloc(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: StreamBuilder<int>( stream: counterBloc.pressedCount, builder: (context, snapshot) { return Text( 'Flutter Counter Bloc Example - ${snapshot.data.toString()}', ); }), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), StreamBuilder<int>( stream: counterBloc.pressedCount, builder: (context, snapshot) { return Text( '${snapshot.data.toString()}', style: Theme.of(context).textTheme.display1, ); }), ], ), ), floatingActionButton: Container( width: 100.0, height: 100.0, child: FloatingActionButton( onPressed: () { counterBloc.incrementCounter.add(null); }, tooltip: 'Increment', child: Text( "+ \n send \n to BLoC", textAlign: TextAlign.center, ), ), ), ); } }
- 我们创建一个单独的类,在其中实现BLoC模式:
3.1所有类的属性和方法都是隐藏的。
3.2为了接收和传输状态,我们使用getter从外部可见的流(但这是关于它们的很酷的文章 )。
class CounterBloc { int _counter; CounterBloc() { _counter = 1; _actionController.stream.listen(_increaseStream); } final _counterStream = BehaviorSubject<int>.seeded(1); Stream get pressedCount => _counterStream.stream; Sink get _addValue => _counterStream.sink; StreamController _actionController = StreamController(); StreamSink get incrementCounter => _actionController.sink; void _increaseStream(data) { _counter += 1; _addValue.add(_counter); } void dispose() { _counterStream.close(); _actionController.close(); } }
如此,我们得到了一个有效的示例,在该示例中,我们通过流发送和接收状态,并在必要的小部件中显示数据,而无需在可视部分中应用任何逻辑。
因此,我们可以将所有计算,数据传输等分开。 从界面。 例如,如果您根据数量向计数器添加不同的标签并从外部数据库中获取它们,那么所有这些逻辑都将已经通过BLoC传递-我们的界面对此一无所知。
注意1:请注意,我们正在创建类的实例> CounterBloc counterBloc = CounterBloc(); 然后我们从中获取数据。 如果我们需要在不同屏幕上(间隔的类中)使用此数据,则可以使用继承的小部件进行传输,也可以从我们的类中创建Singleton。
Github示例代码
好的编码给大家!
延续性
在续集中,我们将状态转移到不同的屏幕上,将数据保存在手机的永久内存中,测试BLoC https://habr.com/en/post/485002/