Dart | Stream的理解 Part1

183 阅读2分钟

image.png 开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

前言

在Dart中,与Java等其他语言最大的不同应该要数Stream和 Future,这俩都是Dart:async库的核心API,对异步提供了非常好的支持。这篇文章我们先首要深入浅出一下 Stream

正文

1.概括

Stream,中文名为“流”。也正如其名,这正是一个流操作,数据从源头来,经过处理,又流出去。这与Android开发中,Kotlin的Flow,RxJava等等有着相同的理念。在大后端也经常用到这个概念,如比较出名的Flink框架,其实就是一个处理流的框架。

用一个图概括:

graph TD
入口 --> Stream对象
Stream对象 --> 出口

问题来了,那如何往入口里塞东西呢?塞了之后Stream操作了什么呢?操作完之后又给了出口,那整体不就相当于是一个观察者模式

首先,我们先回答一下,其实整个Stream是可以理解成一个观察者模式的,出口一旦有东西出来,相关的订阅者就会收到信息,进而对出来的数据进行处理。

而后,我们来实际操作一下如何塞数据,如何处理数据,如何从出口获得数据。

2.操作与使用

首先我们需要创建一个Stream类的对象。构造方法有5种:

  1. Stream.fromFuture,从Future创建新的单订阅流,当future完成时将触发一个data或者error,然后使用Down事件关闭这个流。
  2. Stream.fromFutures,从一组Future创建一个单订阅流,每个future都有自己的data或者error事件,当整个Futures完成后,流将会关闭。如果Futures为空,流将会立刻关闭。
  3. Stream.fromIterable,创建从一个集合中获取其数据的单订阅流。
  4. 直接使用StreamController,其中已经包含一个Stream对象。调用StreamController.stream即可。
  5. 通过生成器创建流。async* 标记的方法称为异步生成器,在其中可以通过yield生成单个元素,yield*生成多个元素,最终汇集成流。

限于篇幅,我们本次着重介绍第四种使用方法。

创建Controller。

var _controller = StreamController<List<Passage>>.broadcast();

随后,获得入口passageSink

passageSink = _controller!.sink as StreamSink<List<Passage>>;

往入口丢数据

passageSink!.add(result);

获得Stream对象

stream = _controller!.stream as Stream<List<Passage>>;

要消费这个Stream的话,就有很多种方法了,

我们这里使用StreamBuilder进行消费。

...
StreamBuilder<List<Passage>>(
    initialData: null, //初始的数据
    stream: _passageViewModel.stream,
...

这样,我们实现了基本的Stream使用流程。