Stream和 Future都是Dart:async库的核心API,对异步提供了很是好的支持。网络
我思考了好久,究竟应该如何向你们介绍Stream(流)。由于Stream很是有用,它是为处理异步事件而生的。而在应用中有大量的场景须要使用异步事件,例如请求网络,和用户交互等等,它们都没法同步完成。Stream可以极大的帮助咱们处理这些问题。😍异步
可是对于刚接触的新手来讲,流确实足够抽象,以致于你们须要花费很是多的时间来理解它。async
因此我将会尽我所能向你们介绍Stream。函数
Stream很是有特色但却不太好理解,我与其按照字面意思把它看做流,更愿意把它当作一个工厂或者是机器。ui
整个过程,时间都是一个不肯定因素,咱们随时均可以向这个机器的入口放东西进去,放进去了之后机器进行处理,可是咱们并不知道它多久处理完。因此出口是须要专门派人盯着的,等待机器流出东西来。整个过程都是以异步的眼光来看的。spa
✈️咱们将机器模型转化成Stream 3d
经过这个例子,相信你们对流应该都有了基础印象,那么要解释后面的东西就不难了。code
stream有三个构造方法:orm
Stream.fromFuture:从Future建立新的单订阅流,当future完成时将触发一个data或者error,而后使用Down事件关闭这个流。cdn
Stream.fromFutures:从一组Future建立一个单订阅流,每一个future都有本身的data或者error事件,当整个Futures完成后,流将会关闭。若是Futures为空,流将会马上关闭。
Stream.fromIterable:建立从一个集合中获取其数据的单订阅流。
Stream.fromIntreable([1,2,3]);
复制代码
监听一个流最多见的方法就是listen。当有事件发出时,流将会通知listener。Listen方法提供了这几种触发事件:
若是你想建立一条新的流的话,很是简单!😀 使用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流出时,打印这个data
StreamSubscription subscription =
controller.stream.listen((data)=>print("$data"));
controller.sink.add(123);
复制代码
输出: 123
你须要将一个方法交给stream的listen函数,这个方法入参(data)是咱们的StreamController处理完毕后产生的结果,咱们监听出口,并得到了这个结果(data)。这里可使用lambda表达式,也能够是其余任何函数。
(这里我为了方便区分,把listen说成函数,(data)=>print(data)说成方法,实际上是一个东西。)
假如你已经有了一个流,你能够经过它转化成为一条新的流。很是简单!流提供了map(),where(),expand(),和take()方法,可以轻松将已有的流转化为新的流。
若是你想要筛选掉一些不想要的事件。例如一个猜数游戏,用户能够输入数字,当输入正确的时候,咱们作出必定反应。而咱们必须筛选掉全部错误的答案,这个时候咱们可使用where筛选掉不须要的数字。
stream.where((event){...})
复制代码
where函数接收一个事件,每当这个流有东西流到where函数的时候,这就是那个事件。咱们或许根本不须要这个事件,可是必须做为参数传入。
若是你想要控制这个流最多能传多少个东西。好比输入密码,咱们可能想让用户最多输四次,那么咱们可使用take来限制。
stream.take(4);
复制代码
take函数接收一个int,表明最多能通过take函数的事件次数。当传输次数达到这个数字时,这个流将会关闭,没法再传输。
若是你须要更多的控制转换,那么请使用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经过的信息,而后进行处理返回一条新的流。
而后咱们监听transform以后的流,当转换好的event流出时,咱们打印这个event,这个event就是咱们刚才add进sink的数据。onError可以捕捉到咱们add进去的err。
流有两种
单个订阅流在流的整个生命周期内仅容许有一个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. 单订阅流不能有多个收听者。
广播流容许任意数量的收听者,且不管是否有收听者,他都能产生事件。因此中途进来的收听者将不会收到以前的消息。
若是多个收听者想要收听单个订阅流,请使用asBroadcastStream在非广播流之上建立广播流。
若是在触发事件时将收听者添加到广播流,则该侦听器将不会接收当前正在触发的事件。若是取消收听,收听者会当即中止接收事件。
通常的流都是单订阅流。从Stream继承的广播流必须重写isBroadcast 才能返回true。
StreamController controller = StreamController();
//将单订阅流转化为广播流
Stream stream = controller.stream.asBroadcastStream();
stream.listen((data)=> print(data));
stream.listen((data)=> print(data));
controller.sink.add(123);
复制代码
输出: 123 123
以上就是关于Dart中Stream的简单介绍,若是你还有任何疑问或者建议,欢迎在下方评论区或者邮箱告诉我!我会在24小时内尽快联系您😉
下一篇文章我将向你们介绍一种很是棒的状态管理方式,它是Google团队力推的状态管理方法,我认为它真的很酷!
因此,准备好迎接BLoC了吗😎