前言:Stream和Future均属于dart.async下的核心库,是dart提供的异步操作类。
正文:
一、Stream创建方式
1、Stream.fromFuture通过future对象创建
Stream.fromFuture(init(1));
//初始化函数
Future init(int a) async{
await Future.delayed(Duration(seconds: 10 - a));
}
2、Stream.fromIterable通过集合创建
Stream.fromIterable([1, 2, 3]);
3、Stream.fromFutures通过Future集合创建
Stream.fromFutures([init(1), init(2)]);
4、Stream.periodic通过Duration对象创建
//间隔为1秒的无限循环
var stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream.listen((event) {
print("****$event");
});
二、Stream使用
1、stream.take设置事件总数
Stream<int> stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.take(4); //一共执行4次事件
stream.listen((event) {
print("****$event");
});
2、stream.takeWhile当不满足条件时终止
Stream<int> stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.takeWhile((data) {
return data < 4;//一共执行4次事件
});
stream.listen((event) {
print("****$event");
});
3、stream.skip跳过前几条事件
Stream<int> stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.take(4);
stream = stream.skip(2);//跳过前两个事件
stream.listen((event) {
print("****$event");
});
4、stream.skipWhile跳过满足条件的事件
Stream<int> stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.take(4);
stream = stream.skipWhile((data){
return data < 2;//跳过前两个事件
});
stream.listen((event) {
print("****$event");
});
5、stream.toList转成数据集合
Stream<int> stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.take(4);
List<int> list = await stream.toList();//异步操作需要await
print("****${list.length}");
6、stream.listen监听事件
var future1 = Future.delayed(Duration(seconds: 1), (){
return "Future 1";
});
var future2 = Future.delayed(Duration(seconds: 2), (){
throw "Future 2 error";
});
var future3 = Future.delayed(Duration(seconds: 3), (){
return "Future 3";
});
Stream<String> stream = Stream.fromFutures([future1, future2, future3]);
stream.listen((event) {//每个事件成功回调(必须参数)
print("****$event");
}, onError: (e) {//每个事件失败回调
print("****$e");
}, onDone: () {//所有事件完成回调
print("****onDone");
});
注:与future.wait区别在于stream.listen无论是否存在事件失败都会回调onDone而future.wait只有所有事件均成功才会回调,相同点是每个事件均会执行(且并发执行),以下是future.wait的用法
var future1 = Future.delayed(Duration(seconds: 1), () {
print("执行事件1");
return "Future 1";
});
var future2 = Future.delayed(Duration(seconds: 2), () {
print("执行事件2");
throw "Future 2 error";
});
var future3 = Future.delayed(Duration(seconds: 5), () {
print("执行事件3");
return "Future 3";
});
Future.wait([future1, future2, future3]).then((results) {
print("results:$results");//所有事件均成功执行后回调
}).catchError((e) {
print("catchError:$e");//存在失败事件则会回调
});
7、stream.forEach遍历事件
var stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.take(5);
stream.forEach((element) {//同listener但只回调onData
print("****$element");
});
8、stream.length事件个数
var stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.take(5);
var length = await stream.length;//异步操作需要await
print("******$length");
9、stream.where执行满足条件的事件
var stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.where((event) => event < 5);//事件执行5次
stream.forEach((element) {
print(element);
});
10、stream.map数据转换
var stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.map((event) => event + 3);//对每个数据加3
stream.forEach((element) {
print(element);
});
11、stream.expand事件扩展
var stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.take(3);
stream = stream.expand((element) => [element, element]);
stream.forEach((element) {
print(element);//输出0 0 1 1 2 2
});
12、stream.transform数据类型转换
var stream = Stream.periodic(Duration(seconds: 1), (data) => data);
stream = stream.take(3);
var stf = StreamTransformer<int, String>.fromHandlers(handleData: (data, sink) {
switch (data) {//将int转string
case 0:
sink.add("zero");
break;
case 1:
sink.add("one");
break;
case 2:
sink.add("two");
break;
}
});
stream.transform(stf).forEach((element) {
print(element);
});
三、StreamConstroller使用
1、单订阅模式(只允许一个监听即使取消了也不能再次订阅)
StreamController sc = StreamController();
StreamSubscription ss = sc.stream.listen((event) {
print(event);//监听事件
});
/*即使取消之前的监听也不能再进行监听
ss.cancel();
sc.stream.listen((event) {
print(event);
});*/
sc.sink.add("one");//发送事件
sc.close();
2、多订阅模式
(1)直接创建方式
StreamController sc = StreamController.broadcast();
sc.stream.listen((event) {
print("监听器1:$event");
});
sc.stream.listen((event) {
print("监听器2:$event");
});
sc.sink.add("one");
sc.close();
(2)单订阅转多订阅方式
StreamController sc = StreamController();
var asBroadcastStream = sc.stream.asBroadcastStream();
asBroadcastStream.listen((event) {
print("监听器1:$event");
});
asBroadcastStream.listen((event) {
print("监听器2:$event");
});
sc.sink.add("one");
sc.close();
四、StreamBuider使用(实现StatelessWidget中更新UI)
class MainApp extends StatelessWidget {
int count = 0;
StreamController sc = StreamController();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: StreamBuilder(
stream: sc.stream,//绑定事件流
builder: (context, snapshot) {//处理事件
return Text("${snapshot.data}");
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
sc.sink.add(++count);//发送事件
},
),
),
);
}
}
注:虽然以上可以使StatelessWidget进行更新,但由于StreamController需要在页面销毁时关闭,而StatelessWidget无销毁回调,所以应在StatefulWidget中使用,可在dispose中进行关闭