# Flutter - Stream
## 基礎概念
Stream和Future都是Dart:async庫的核心API,我們常用於異步的操作。
若把它想成機器以下是他的特點:
1. 一個隨時可以接收東西的入口
2. 這個機器執行的過程可以進行加工
3. 機器做完後產品隨時都有可能出來
4. 先進先出
>
機器 - StreamController
機器入口 - sink,可以使用`add`的方式放入產品
機器出口 - stream,但由於不知道何時會出來所以需要透過`listen`的方式進行監聽
### Stream的種類

#### 單訂閱流Stream
* 只允許有一個listener
* 沒有listener就不會生成事件,即使你仍然在sink.add更多事件。
* listener取消後也不允許再被監聽
* 常用於: 下載,訂閱流來知道下載進度
```dart
StreamController controller = StreamController();
controller.stream.listen((data)=> print(data));
controller.stream.listen((data)=> print(data));
//噴錯: Bad state: Stream has already been listened to. 單訂閱流不能有多個收聽者。
controller.sink.add(123);
```
#### 多訂閱流BroadcastStream
* 允許任意數量的listener
* 無論是否有收聽者,他都能產生事件。所以**中途進來的收聽者將不會收到之前的消息**。
* asBroadcastStream
```dart
StreamController controller = StreamController();
//轉化為廣播流
Stream stream = controller.stream.asBroadcastStream();
stream.listen((data)=> print(data));
stream.listen((data)=> print(data));
controller.sink.add(123);
```
### 如何使用Stream
#### 宣告
```dart
//任一類型
StreamController controller = StreamController();
controller.sink.add(123);
controller.sink.add("xyz");
controller.sink.add(Anything);
//處理int類型
StreamController<int> numController = StreamController();
numController.sink.add(123);
//處理完流記得進行關閉
controller.close();
numController.close();
```
#### 完整流程
```dart
StreamController controller = StreamController();
//監聽出口當有data產生時印出資料
StreamSubscription subscription =
controller.stream.listen((data)=>print("$data"));
controller.sink.add(123);
//處理完記得進行關閉
subscription.cancel();
```
輸出
```
123
```
### 篩選Stream
#### where
```dart
stream.where((event){})
```
#### take
當傳輸次數超過這一個述自將自動關閉
```dart
stream.take(2)
```
### transform
要配合StreamTransformer進行使用,以下範例為輸入**數字**回應**字串**
```dart
StreamController<int> controller = StreamController<int>();
//這邊進行轉換
final transformer = StreamTransformer<int,String>.fromHandlers(
handleData:(value, sink){
if(value==100){
sink.add("bingo");
}
else{ sink.addError('nono try again');
}
});
controller.stream
.transform(transformer)
.listen(
(data) => print(data),
onError:(err) => print(err));
controller.sink.add(23);
//controller.sink.add(100);
```
### StreamBuilder
以下使用計時器當作範例:
```dart
//每隔一秒生成一個數字
Stream<int> counter() {
return Stream.periodic(Duration(seconds: 1), (i) {
return i;
});
}
```
```dart
Widget build(BuildContext context) {
return StreamBuilder<int>(
stream: counter(), //
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('沒有Stream');
case ConnectionState.waiting:
return Text('等待資料...');
case ConnectionState.active:
return Text('active: ${snapshot.data}');
case ConnectionState.done:
return Text('Stream 已關閉');
}
return null; // unreachable
},
);
}
```
## 實作
## 參考資料
https://book.flutterchina.club/chapter7/futurebuilder_and_streambuilder.html#_7-6-1-futurebuilder
https://juejin.cn/post/6844903686737494023
https://juejin.cn/post/6844903689082109960
###### tags: `flutter`