Dart _ 什么是 Stream,安卓开发不得不会
?? StreamController
如果你想创建一条新的流的话,非常简单!?? 使用 StreamController,它为你提供了非常丰富的功能,你能够在 streamController 上发送数据,处理错误,并获得结果!
//任意类型的流 StreamController controller = StreamController();controller.sink.add(123);controller.sink.add("xyz");controller.sink.add(Anything);
//创建一条处理 int 类型的流 StreamController<int> numController = StreamController();numController.sink.add(123);
泛型定义了我们能向流上推送什么类型
的数据。它可以是任何类型!
我们再来看看如何获取最后的结果。
StreamController controller = StreamController();
//监听这个流的出口,当有 data 流出时,打印这个 dataStreamSubscription subscription =controller.stream.listen((data)=>print("$data"));
controller.sink.add(123);
输出: 123
你需要将一个方法交给 stream 的 listen 函数,这个方法入参(data)是我们的 StreamController 处理完毕后产生的结果,我们监听出口,并获得了这个结果(data)。这里可以使用 lambda 表达式,也可以是其他任何函数。
(这里我为了方便区分,把 listen 说成函数,(data)=>print(data)说成方法,其实是一个东西。)
通过 async* 生成 stream
如果我们有一系列事件需要处理,我们也许会需要把它转化为 stream。这时候可以使用 async - yield* 来生成一个 Stream。
Stream<int> countStream(int to) async* {for (int i = 1; i <= to; i++) {yield i;}}
当循环退出时,这个 Stream 也就 done 了。我们可以结合之前说的 await for 更加深刻的体验一下。
你可以在 这里 直接运行我的样例代码。
??Transforming an existing stream
假如你已经有了一个流,你可以通过它转化成为一条新的流。非常简单!流提供了 map(),where(),expand(),和 take()方法,能够轻松将已有的流转化为新的流。
where
如果你想要筛选掉一些不想要的事件。例如一个猜数游戏,用户可以输入数字,当输入正确的时候,我们做出一定反应。而我们必须筛选掉所有错误的答案,这个时候我们可以使用 where 筛选掉不需要的数字。
stream.where((event){...})
where 函数接收一个事件,每当这个流有东西流到 where 函数的时候,这就是那个事件。我们或许根本不需要这个事件,但是必须作为参数传入。
take
如果你想要控制这个流最多能传多少个东西。比如输入密码,我们可能想让用户最多输四次,那么我们可以使用 take 来限制。
stream.take(4);
take 函数接收一个 int,代表最多能经过 take 函数的事件次数。当传输次数达到这个数字时,这个流将会关闭,无法再传输。
transform
如果你需要更多的控制转换,那么请使用 transform()方法。他需要配合 StreamTransformer 进行使用。我们先来看下面一段猜数游戏,然后我会向你解释。
StreamController<int> controller = StreamController<int>();
final transformer = StreamTransformer<int,String>.fromHandlers(handleData:(value, sink){if(value==100){sink.add("你猜对了");}else{ sink.addError('还没猜中,再试一次吧');}});
controller.stream.transform(transformer).listen((data) => print(data),onError:(err) => print(err));
controller.sink.add(23);//controller.sink.add(100);
输出: 还没猜中,再试一次吧
StreamTransformer<S,T>是我们 stream 的检查员,他负责接收 stream 通过的信息,然后进行处理返回一条新的流。
S 代表之前的流的输入类型,我们这里是输入一个数字,所以是 int。
T 代表转化后流的输入类型,我们这里 add 进去的是一串字符串,所以是 String。
handleData 接收一个 value 并创建一条新的流并暴露 sink,我们可以在这里对流进行转化。
我们还可以 addError 进去告诉后面有问题。
然后我们监听 transform 之后的流,当转换好的 event 流出时,我们打印这个 event,这个 event 就是我们刚才 add 进 sink 的数据。onError 能够捕捉到我们 add 进去的 err。
??Stream 的种类
流有两种
"Single-subscription" streams 单订阅流
"broadcast" streams 多订阅流
"Single-subscription" streams
单个订阅流在流的整个生命周期内仅允许有一个 listener。它在有收听者之前不会生成事件,并且在取消收听时它会停止发送事件,即使你仍然在 Sink.add 更多事件。
即使在第一个订阅被取消后,也不允许在单个订阅流上进行两次侦听。
单订阅流通常用于流式传输更大的连续数据块,如文件 I / O.
StreamController controller = StreamController();
controller.stream.listen((data)=> print(data));controller.stream.listen((data)=> print(data));
controller.sink.add(123);
输出: Bad state: Stream has already been listened to. 单订阅流不能有多个收听者。
"Broadcast" streams
广播流允许任意数量的收听者,且无论是否有收听者,他都能产生事件。所以中途进来的收听者将不会收到之前的消息。
如果多个收听者想要收听单个订阅流,请使用 asBroadcastStream 在非广播流之上创建广播流。
如果在触发事件时将收听者添加到广播流,则该侦听器将不会接收当前正在触发的事件。如果取消收听,收听者会立即停止接收事件。
一般的流都是单订阅流。从 Stream 继承的广播流必须重写 isBroadcast 才能返回 true。
StreamController controller = StreamController();//将单订阅流转化为广播流 Stream stream = controller.stream.asBroadcastStream();
stream.listen((data)=> print(data));stream.listen((data)=> print(data));
评论