如何使用Dart的Stream(二)

上一章主要介绍了什么是 Stream以及如何通过StreamController来间接实现Stream的交互。最后介绍了Stream的两种类型。
这一章主要介绍如何在Stream中的常用方法,根据功能我将Stream中的方法分为以下几类:

  1. Stream构造方法
  2. 截取Stream中的部分data
  3. 将Stream中的data进行转换
  4. 校验Stream中的data

Stream构造方法

上一章介绍了通过 StreamController 来操作Stream,但是我们也可以通过它自带的构造函数直接构造Stream对象。在Stream中有3个工厂构造函数:

  1. fromIterable
  2. fromFuture
  3. 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的转换

  1. 直接使用 Steam.map
  2. 通过 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

关注二维码,发私信申请加入 Flutter 讨论群
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值