Flutter Dart之Stream

860 阅读3分钟

本文仅仅是对理解Dart 异步事件流 Stream这一文做的学习笔记,更多详情请移步原文

基本概念

Stream: 异步事件流。表示发出的一系列异步事件。

Steam与集合的关系

  • Dart中的集合(Iterable或Collection),表示一系列的对象集合。你可以主动的去迭代()里面的对象(eg: 一个List对象,可以主动的遍历);

  • Stream也是对象的集合,不同的是它是异步的事件对象集合。例如:文件、套接字这种 IO 数据的非阻塞输入流(input data),或者用户界面上用户触发的动作(UI事件)。Stream是主动事件,并不是你想要就能like拿到的。同时为了能得到事件,需要用一个listener(即callback),做好事件接收准备。

总之二者有很多相同的方法

Stream中数据

  • 程序世界中只有两种东西:数据对数据的操作
  • dart中所有事物都是对象,所以数据也是一定是对象。

Stream 与 Future

  • 二者都是Dart中处理异步的核心API
  • Future表示稍后获得的一个数据,所有异步的操作返回值都是Future。但是Future只能表示一次异步获得的数据
  • Stream表示多次异步获得的数据。eg: 界面上的按钮点击事件就是一个Stream,因为它能响应多次
  • Stream处理过程占用的内存,Future占用的内存较
  • 简单地说,Future将返回一个值,而Stream将返回多次值

基本使用

  • 生成 截屏2022-01-17 下午8.14.52.png 截屏2022-01-17 下午8.15.19.png 由上面的截图可知,Stream有4中构造方法,分别是Future、Futures、Iterable或定时触发动作作为 Stream 的事件源构造 Stream。eg:
var data = [1, 2, 3, 4];
var stream = new Stream.fromIterable(data);
  • 订阅

onData,处理收到的数据的 callback

onError,处理遇到错误时的 callback

onDone,结束时的通知 callback

cancelOnError,遇到第一个错误时是否停止(也就是取消订阅),默认为false

  StreamSubscription<T> listen(void onData(T event)?,
{Function? onError, void onDone()?, bool? cancelOnError});

var data = [1, 2, 3, 4];
var stream = new Stream.fromIterable(data);

stream.listen((e)=>print(e), onDone: () => print('Done'), onError: () => print('onError'), cancelOnError: true );
// => 1, 2, 3, 4
// => Done

在结束的同时(收到 onDone 事件之前),所有的订阅者都被取消了订阅,此时 Stream 上便没有订阅者了。允许对一个已经结束了的 Stream 再添加订阅者(尽管没什么意义),此时只会立刻收到一个 onDone 事件

高级订阅管理

提前取消处理

listen() 方法会返回一个 StreamSubscription 对象,用于提供对订阅的管理控制。onData、onError和onDone 这3个方法分别用于设置(如果listen方法中的参数为null)或覆盖对应的 callback。cancel、pause和resume分别用于取消订阅、暂停和继续。

var data = [1, 2, 3, 4];
var stream = new Stream.fromIterable(data);
var sub = stream.listen(null);
sub.onData((e){
    if(e > 2) {
        sub.cancel();
    } else {
        print(e);
    }
});
sub.onDone(()=>print('done'));
// => 1, 2
// no 'done', because stream is cancel.

Steam的两种订阅模式:单订阅(single)和广播(broadcast

单订阅就是只能有一个订阅者,而广播是可以有多个订阅者.

  • 单订阅类似于点对点,在订阅者出现之前会持有数据,在订阅者出现之后就才转交给它。

  • 广播类似于发布订阅模式,可以同时有多个订阅者,当有数据时就会传递给所有的订阅者,而不管当前是否已有订阅者存在。

  • 处于单订阅模式下,同一个stream上的listen方法只能调用一次,调用第二次就会报错.通过 Stream.asBroadcastStream() 可以将一个单订阅模式的 Stream 转换成一个多订阅模式的 Stream,isBroadcast 属性可以判断当前 Stream 所处的模式。

assert(stream.isBroadcast == false);
stream.first.then(print);
//调用第二次就会报错
stream.last.then(print);// Bad state: Stream already has subscriber.

通过Stream.asBroadcastStream() 转成多订阅

var bs = stream.asBroadcastStream();
assert(bs.isBroadcast == true);
bs.first.then(print);
bs.last.then(print);
// OK => 1, 4