上一章主要介绍了什么是 Stream以及如何通过StreamController来间接实现Stream的交互。最后介绍了Stream的两种类型。
这一章主要介绍如何在Stream中的常用方法,根据功能我将Stream中的方法分为以下几类:
- Stream构造方法
- 截取Stream中的部分data
- 将Stream中的data进行转换
- 校验Stream中的data
Stream构造方法
上一章介绍了通过 StreamController 来操作Stream,但是我们也可以通过它自带的构造函数直接构造Stream对象。在Stream中有3个工厂构造函数:
- fromIterable
- fromFuture
- periodic
这三个构造函数分别通过一个Iterable、 Future、或定时触发动作作为 Stream 的事件源构造对象。
fromIterable 示例
var data = [1,2,3,4,5]; // 集合数据
var stream = new Stream.fromIterable(data); // 根据集合创建Stream
// 设置监听者
stream.listen((value) => print("Received: $value"));
打印:
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
fromFuture 示例
main() {
print("正在创建 Stream...");
Stream<String> stream = new Stream.fromFuture(getData());
print("Stream 创建成功");
stream.listen((data) {
print("收到: " + data);
}, onDone: () {
print("任务完成");
}, onError: (error) {
print("Error 发生");
});
print("同步代码执行中。。。");
}
Future<String> getData() async {
await Future.delayed(Duration(seconds: 5)); //模拟延时操作
print("获取网络数据成功");
return "This a test data";
}
打印:
正在创建 Stream...
Stream 创建成功
同步代码执行中。。。
// 5秒之后打印如下日志
获取网络数据成功
收到: This a test data
任务完成
periodic 示例
void main(){
test();
}
test() async{
// 使用 periodic 创建流,第一个参数为间隔时间,第二个参数为回调函数
Stream<int> stream = Stream<int>.periodic(Duration(seconds: 1), callback);
stream.forEach((item) => print(item));
}
// 可以在回调函数中对值进行处理,这里直接返回了
int callback(int value){
return value;
}
打印:
// 每隔1秒钟打印一行日志
0
1
2
3
4
截取Stream中的部分data
在Stream中有一些很方便的方法,可以实现从Stream中提取出我们所需要的数据集合。我还是用上文中创建的stream来举例:
var data = [1,2,3,4,5]; // 集合数据
var stream = new Stream.fromIterable(data);
where 过滤出符合 where
中条件的数据
stream
.where((value) => value % 2 == 0) // 判断value对2取余等于0
.listen((value) => print("where: $value"));
打印:
where 2
where 4
take 提取出Stream中的前X个数据
stream
.take(3) // 取出Stream中前3个元素
.listen((value) => print("take: $value"));
打印:
take: 1
take: 2
take: 3
takeWhile 只要takeWhile
中的条件为true,则将此数据假如到Stream中
stream
.takeWhile((value) => value < 3) // 取出Stream中小于3的所有数据
.listen((value) => print("takeWhile: $value"));
打印:
takeWhile: 1
takeWhile: 2
skip 跳过Stream中的前X个数据
stream
.skip(3) // 跳过Stream中的前3个数据
.listen((value) => print("skip: $value"));
打印:
skip: 4
skip: 5
skipWhile 只要skipWhile
中的条件为true,则跳过此数据
stream
.skipWhile((value) => value < 3) // 跳过所有值小于3的数据
.listen((value) => print("skipWhile: $value"));
打印:
skipWhile: 3
skipWhile: 4
skipWhile: 5
distinct 去除Stream中重复的数据
StreamController streamController = StreamController();
streamController.sink.add(1);
streamController.sink.add(2);
streamController.sink.add(2);
streamController.sink.add(3);
Stream newStream = streamController.stream.distinct();
newStream.listen((value) {
print("distinct: $value");
});
打印:
distinct: 1
distinct: 2
distinct: 3
将Stream中的data进行转换
有两种方式可以实现data的转换
- 直接使用
Steam.map
- 通过
StreamTransformer.fromHandlers
map
// 在元数据的基值上做 +1 操作
Stream newStream = stream.map((value) => value + 1);
newStream.listen((value) {
print("map : $value");
});
打印:
map : 2
map : 3
map : 4
map : 5
map : 6
StreamTransformer.fromHandlers(…) 当需要转换数据的逻辑比较复杂,我们可以考虑调用Stream.transform()
方法传入一个StreamTransformer对象来进行数据转换。其中数据转草操作都在StreamTransformer中fromHandlers
的方法中
// define a stream transformer
var transformer = new StreamTransformer.fromHandlers(handleData: (value, sink) {
// 用传入的data分别狗粮Message和Body字符串,并重新添加到sink中
sink.add("Message: $value");
sink.add("Body: $value");
});
// transform the stream and listen to its output
stream.transform(transformer).listen((value) => print("transform : $value"));
打印:
transform : Message: 1
transform : Body: 1
transform : Message: 2
transform : Body: 2
transform : Message: 3
transform : Body: 3
transform : Message: 4
transform : Body: 4
transform : Message: 5
transform : Body: 5
校验Stream中的data
有时候,我们需要对Stream中的数据进行相关条件的校验,Stream提供了一些方法来实现这方面的需要,主要包括以下几个方法:
any 只要Stream中有一个数据满足条件则返回 true
stream
.any((value) => value < 5)
.then((result) => print("Stream中有数据 < 5 返回 $result"));
打印
Stream中有数据 < 5 : true
every 判断Stream中所有的数据满足某条件
broadcastStream
.every((value) => value < 5)
.then((result) => print("所有数据都 < 5 返回 $result"));
打印
所有数据都 < 5 返回 false
contains 判断Stream中是否包含某数据
broadcastStream
.contains(4)
.then((result) => print("Stream中包含 4 返回 $result")); // true
打印
Stream中包含 4 返回 true