iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
Software Development

Dart 語言 - 開啟 Flutter 的鑰匙系列 第 24

Day 24:異步處理 Part2-Stream

在 Dart 中有兩種異步類別,一種是 Future ,另一種則是 Stream ,在上一篇我們知道 Future 是針對耗時的工作,在工作完成時才回傳結果。並且可以利用 async 關鍵字建立異步函數,並在該函數使用await 關鍵字來等待 Future的回傳值。

另一個異步類別為 Stream

什麼是 Stream ?

Stream 是用來接收一連串的事件,註冊 Stream 的 監聽器 (Listener) 之後,若 Stream 有事件,則將會通知監聽器。

當全部的 Stream 事件結束後,將會發送 Done 訊號給監聽器。

其中 Stream 分為兩種,一種為單一訂閱 (Single-subscription) stream,另一種則為廣播 (Broadcast) stream。

單一訂閱 stream

在Stream的生命週期裡,只允許一個監聽器監聽其變化。需要注意的是,Stream 會在有人註冊之後才開始發送事件,當監聽器取消訂閱時,將不再發送事件,縱使 Stream 的事件還沒有完全發送完畢。

另外,同一個 Stream 不允許多次註冊監聽器,就算是第一個監聽器已經被取消也是一樣。

通常用在傳送傳輸量較大的連續數據塊,例如檔案的 I/O。

廣播 stream

允許多個監聽器註冊,當 Stream 有事件進來的時候,會立刻發送事件,縱使沒有監聽器註冊也會發。

獲得 Stream 的方法

  • 使用 Stream 的建構函數
  • 使用 StreamController
  • 使用 async* 函數

Stream 建構函數

  • Stream.fromFuture(Future future)
  • Stream.fromFutures(Iterable<Future> futures)
  • Stream.fromIterable(Iterable element)
  • ...

範例:

Stream.fromFuture(Future future)

final stream1 = Stream.fromFuture(Future.delayed(Duration(seconds:1), ()=>10));

Stream.fromFutures(Iterable<Future> futures)

List<Future<int>> generateFutures() =>
    List<Future<int>>.generate(10, (index) => Future.value(index));

final stream2 = Stream.fromFutures(generateFutures());

Stream.fromIterable(Iterable element)

final stream3 = Stream.fromIterable(List<int>.generate(5, (index) => 5*index));

我們利用建構函數建立了三個 Stream,那麼要如何監聽它們呢?

listen()

直接呼叫 stream 的 listen 函數

StreamSubscription<T> listen(void onData(T event)?,
      {Function? onError, void onDone()?, bool? cancelOnError});
  • listen 函數會回傳事件 (onData)、錯誤 (onError)、完成 (onDone)。

例如:

stream.listen((event) => print(event));

將會在每一個事件到來的時候,執行 print(event) 這個動作。

await for

除了利用 listen 函數來處理外,我們還可以使用 asyncawait for 來處理。

範例如下:

Future<int> sumStream(Stream<int> stream) async {
  var sum = 0;
  await for (var value in stream) {
    sum += value;
  }
  return sum;
}
  • await for 可以將 Stream 使用 forEach 的方式拆解,接者回傳一個Future 的值。

StreamController

在 StreamController 中,利用 sink 將資料加進 (add) Stream裡:

StreamController<int> numController = StreamController();
numController.sink.add(777);

接者用 stream 將 controller 轉為 stream

numController.stream.listen((value) => print(value));
//777

async*

利用關鍵字 async*yield 也可以產生一個 Stream

Stream<int> increaseStream() async* {
  for (int i = 1; i <= 10; i++) {
    yield i;
  }
}

小結

本篇文章介紹了如何使用 Stream 以及建立 Stream,Stream 跟 Future 不同的是,因為 Stream 是由多個 Future 事件組成的,所以我們需要用 listener 來監聽,當事件到來時,我們才可以取得資料。

另外,在 Future 中,我們使用關鍵字 async 來處理 Future 函數,在

Stream 上需要加上星號 async*,代表多個 Future 事件。使用 async* 要記得使用 yield 而不是 await


上一篇
Dart23:異步處理
下一篇
Day 25:擴充方法 (Extension method)
系列文
Dart 語言 - 開啟 Flutter 的鑰匙30

尚未有邦友留言

立即登入留言