先大概说说Stream的概念,这个Stream就是类似平常大家用的比较多的RxJava、RxSwift等框架的思路,它是一个异步数据的源,它可以接受任何数据,通过StreamController可以给这个Stream添加数据,如果这个Stream有监听者就会接收到数据。 代码如下:
import 'dart:async';
void main() {
// 初始化一个Stream controller
final StreamController ctrl = StreamController();
// 添加一个监听
ctrl.stream.listen((data) => print('$data'));
// 往Stream中添加数据
ctrl.sink.add('这个是字符串'); //字符串类型
ctrl.sink.add(1234);//int 类型
ctrl.sink.add({'name': '姓名', 'content': 'json对象也行'});//对象类型
ctrl.sink.add(123.45); //double类型
// StreamController用完后需要释放
ctrl.close();
}
以前我就经常说Flutter有各种个样的Widget,只有你想不到的。所以既然有Stream,就有对应的Widget,叫StreamBuilder。它本身是一个Widget,然后会监听一个Stream,只要这个Stream有数据变化,它内部的UI就会根据这个新的数据进行变化,完全不需要setState((){})
。
这里我就拿平常很常见的一个例子来看看这个StreamBuilder怎么用的:发送验证码的按钮
首先建一个类处理倒计时的业务,这个有点类似BLoC模式,将UI和业务逻辑分离。
class CountTime {
StreamController<int> _controller;
final int maxSecond;
CountTime({this.maxSecond = 60}){
_controller = StreamController();
}
///
///提供一个stream
///
Stream<int> get countTimeStream => _controller.stream;
///
/// 开始倒计时
///
startCount() async {
if (maxSecond <= 0) {
return;
}
for(var i = maxSecond; i >= 0; i--){
Duration duration;
if (i == maxSecond) {
duration = Duration(seconds: 0);
}else {
duration = Duration(seconds: 1);
}
await Future.delayed(duration, (){
return i
}).then((s){
_controller.sink.add(s);
});
}
}
dispose() {
_controller.close();
}
}
这个业务逻辑类里面就是定义了一个StreamController,控制倒计时的输出,它提供一个countTimeStream供外部调用。 这时候在界面UI上,我们使用StreamBuilder监听这个Stream:
@override
void initState() {
//初始化业务类
_countTime = CountTime(maxSecond: 60);
super.initState();
}
@override
void dispose() {
//销毁
_countTime.dispose();
super.dispose();
}
...
StreamBuilder(
//监听的Stream
stream: _countTime.countTimeStream,
//初始化值
initialData: 0,
//根据Stream变化进行修改的UI
builder: (context, snap) {
var buttonText;
if (snap.data == 0) {
onclick = (){
_countTime.startCount();
};
buttonText = '发送验证码';
}else {
onclick = null;
buttonText = '${snap.data} 秒后可以再次发送';
}
return FlatButton(
onPressed: onclick,
child: Text(buttonText),
color: Colors.lightBlue,
textColor: Colors.white,
disabledColor: Colors.grey,
disabledTextColor: Colors.white30,
);
}
)
这个倒计时按钮就完成了。