为处理异步事件而生的。例如请求网络,和用户交互等等,Stream能够极大的帮助我们处理这些问题。
通俗讲法:水管。出入口进数据,由出口看效果,如下图所示。图例中,在入口放东西进去,然后在出口看流出来的东西。中间的过程是个加工厂,具有不确定性因素(如时间)。
根据上图示例我们可以小总结一下Stream的特点:
整个过程,时间都是一个不确定因素,我们随时都可以向这个机器的入口放东西进去,放进去了以后机器进行处理,但是我们并不知道它多久处理完。所以出口是需要专门派人盯着的,等待机器流出东西来。整个过程都是以异步的眼光来看的。
stream有三个构造方法:
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流出时,打印这个dataStreamSubscription 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。
"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));controller.sink.add(123);复制代码
输出: 123 123
以上就是关于Dart中Stream的简单介绍,如果你还有任何疑问或者建议,欢迎在下方评论区或者邮箱告诉我!我会在24小时内尽快联系您