|
| 1 | +### StreamBuilder介绍 |
| 2 | +前面介绍过FutureBuilder,它是一个Widget控件,提供了异步数据获取与ui更新的能力,StreamBuilder与FutureBuilder类似[[官方文档]]([https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html](https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html) |
| 3 | +),也是一个Widget控件,不一样的是FutureBuilder依靠Future来做异步数据获取,而StreamBuilder则是依赖Stream来做异步数据获取。 |
| 4 | + |
| 5 | +### Stream介绍 |
| 6 | +在讲StreamBuilder前得先介绍下Stream这个东西。通俗点讲,Stream就是个事件流,有点类似于RxJava,它允许我们从一端发射一个事件,从另外一端去监听事件的变化,通过Stream我们可以在Flutter上设计出基于事件流驱动的响应式代码逻辑。 |
| 7 | + |
| 8 | +### Stream的简单实用 |
| 9 | +事实上Stream并是不Flutter的产物,而是由Dart提供的,Stream是一个抽象的接口,Dart提供了StreamController接口类可以让我们方便的使用Stream,步骤大致如下: |
| 10 | +- 创建`StreamController` |
| 11 | +- 获取`StreamSink `用作发射事件 |
| 12 | +- 获取`Stream`用作事件的监听 |
| 13 | +- 获取`StreamSubscription `用作管理监听,关闭暂停等 |
| 14 | +```dart |
| 15 | + StreamSubscription<String> subscription; |
| 16 | + //创建StreamController |
| 17 | + var streamController = StreamController<String>(); |
| 18 | + // 获取StreamSink用于发射事件 |
| 19 | + StreamSink<String> get streamSink => streamController.sink; |
| 20 | + // 获取Stream用于监听 |
| 21 | + Stream<String> get streamData => streamController.stream; |
| 22 | +
|
| 23 | + //监听事件 |
| 24 | + subscription = streamData.listen((value) { |
| 25 | + // do something |
| 26 | + }); |
| 27 | +
|
| 28 | + //发射一个事件. |
| 29 | +streamSink.add(index.toString()); |
| 30 | +``` |
| 31 | + |
| 32 | +### StreamBuilder的使用介绍 |
| 33 | +- 构造方法 |
| 34 | +```dart |
| 35 | +StreamBuilder({Key key, T initialData, Stream<T> stream, @required AsyncWidgetBuilder<T> builder }) |
| 36 | +``` |
| 37 | +`initialData` : 默认初始化数据 |
| 38 | +`stream` : stream事件流对象 |
| 39 | +`builder` : 负责根据不同状态创建对应ui的方法实现 |
| 40 | +AsyncWidgetBuilder前面在讲FutureBuilder的时候已经介绍过,这里不再赘述。 |
| 41 | +- 其他方法 |
| 42 | +`afterConnected`:返回一个AsyncSnapshot,当订阅了stream时会回调此AsyncSnapshot |
| 43 | +`afterData`:返回一个AsyncSnapshot,当stream有事件触发时会回调此AsyncSnapshot |
| 44 | +`afterDisconnected`:返回一个AsyncSnapshot,当取消订阅stream时会回调此AsyncSnapshot |
| 45 | +`afterDone`:返回一个AsyncSnapshot,当stream被关闭时会回调此AsyncSnapshot |
| 46 | +`afterError`:返回一个AsyncSnapshot,stream发生错误时会回调此AsyncSnapshot |
| 47 | + |
| 48 | +StreamBuilder 内部已经帮我们完成了stream的订阅与取消订阅,在initState的时候进行事件的订阅,在dispose的时候进行事件的反订阅,源码在`_StreamBuilderBaseState`里,关键过程大致如下 |
| 49 | +```dart |
| 50 | +void initState() { |
| 51 | + super.initState(); |
| 52 | + _summary = widget.initial(); |
| 53 | + _subscribe(); |
| 54 | + } |
| 55 | +
|
| 56 | +void dispose() { |
| 57 | + _unsubscribe(); |
| 58 | + super.dispose(); |
| 59 | + } |
| 60 | +void _subscribe() { |
| 61 | + if (widget.stream != null) { |
| 62 | + _subscription = widget.stream.listen((T data) { |
| 63 | + setState(() { |
| 64 | + _summary = widget.afterData(_summary, data); |
| 65 | + }); |
| 66 | + }, onError: (Object error) { |
| 67 | + setState(() { |
| 68 | + _summary = widget.afterError(_summary, error); |
| 69 | + }); |
| 70 | + }, onDone: () { |
| 71 | + setState(() { |
| 72 | + _summary = widget.afterDone(_summary); |
| 73 | + }); |
| 74 | + }); |
| 75 | + _summary = widget.afterConnected(_summary); |
| 76 | + } |
| 77 | + } |
| 78 | + void _unsubscribe() { |
| 79 | + if (_subscription != null) { |
| 80 | + _subscription.cancel(); |
| 81 | + _subscription = null; |
| 82 | + } |
| 83 | + } |
| 84 | +``` |
| 85 | +从上面的源码里面我们也可以清楚得看见StreamBuilder的各个回调方法的调用过程。 |
| 86 | + |
| 87 | +### 完整例子 |
| 88 | +下面给出一个完整的代码例子,我们的页面在初始化的时候创建了`StreamController`,页面上面有个按钮,当点击按钮的时候就会发射出一个事件,StreamBuilder订阅了这个事件,并且把data打印出来 |
| 89 | +```dart |
| 90 | +import 'dart:async'; |
| 91 | +
|
| 92 | +import 'package:flutter/material.dart'; |
| 93 | +import 'dart:io'; |
| 94 | +import 'dart:convert'; |
| 95 | +
|
| 96 | +/** |
| 97 | + * Created by nls on 2019/7/20. |
| 98 | + * Nothing. |
| 99 | + */ |
| 100 | +class StreamBuilderDemo extends StatelessWidget { |
| 101 | + @override |
| 102 | + Widget build(BuildContext context) { |
| 103 | + return MaterialApp( |
| 104 | + theme: ThemeData(primaryColor: Colors.blue), |
| 105 | + home: HomeWidget()); |
| 106 | + } |
| 107 | +} |
| 108 | +
|
| 109 | +class HomeWidget extends StatefulWidget { |
| 110 | + @override |
| 111 | + State createState() { |
| 112 | + return HomeState(); |
| 113 | + } |
| 114 | +} |
| 115 | +
|
| 116 | +class HomeState extends State<HomeWidget> { |
| 117 | + var index = 0; |
| 118 | + StreamSubscription<String> subscription; |
| 119 | + //创建StreamController |
| 120 | + var streamController; |
| 121 | + // 获取StreamSink用于发射事件 |
| 122 | + StreamSink<String> get streamSink => streamController.sink; |
| 123 | + // 获取Stream用于监听 |
| 124 | + Stream<String> get streamData => streamController.stream; |
| 125 | +
|
| 126 | + void onFloatActionButtonPress() { |
| 127 | + //发射一个事件. |
| 128 | + streamSink.add(index.toString()); |
| 129 | + index++; |
| 130 | + } |
| 131 | +
|
| 132 | + @override |
| 133 | + void initState() { |
| 134 | + super.initState(); |
| 135 | + streamController = StreamController<String>(); |
| 136 | + streamSink.add("0"); |
| 137 | + } |
| 138 | +
|
| 139 | + @override |
| 140 | + Widget build(BuildContext context) { |
| 141 | + return Scaffold( |
| 142 | + appBar: AppBar(title: Text('streamBuilder')), |
| 143 | + body: Center( |
| 144 | + child: Column( |
| 145 | + mainAxisAlignment: MainAxisAlignment.center, |
| 146 | + children: <Widget>[ |
| 147 | + StreamBuilder<String>( |
| 148 | + stream: streamData, |
| 149 | + builder: (BuildContext context, AsyncSnapshot<String> snapshot) { |
| 150 | + return Text('Result: ${snapshot.data}'); |
| 151 | + } |
| 152 | + ) |
| 153 | + ], |
| 154 | + ) |
| 155 | + ), |
| 156 | + floatingActionButton: FloatingActionButton( |
| 157 | + onPressed: onFloatActionButtonPress, |
| 158 | + child: Icon(Icons.add)) |
| 159 | + ); |
| 160 | + } |
| 161 | +} |
| 162 | +``` |
0 commit comments