Flutter Future Stream (Flutter Roadmap Futures Streams)

## はじめに
Flutterを網羅的に学習するにあたって[Roadmap](https://roadmap.sh/flutter)を使って学習を進めることにしました。

この記事では、Flutter初学者やこれからFlutterを学習し始める方に向けて、**Future Stream**についてまとめています。

RoadmapはFlutterだけでなく、他の言語やスキルのロードマップも提供されており、何から学習して良いか分からないと悩んでいる方にとって有用なサイトになっています。
ぜひ[Roadmap](https://roadmap.sh/)を利用して学習してみてください。

## Roadmapとは

簡潔に言えば、Roadmap.shは学習者にとっての**ガイドブック**であり、**学習の方向性を提供する学習ロードマップサイト**です。

初心者から上級者まで、ステップバイステップでスキルを習得するための情報が提供されています。

学習の進め方が分かりやすく示されているだけでなく、個々の項目に参考資料やリソースへのリンクも提供されているので、学習者は目標を設定し、自分自身のペースで学習を進めることができます。

## Future / Stream
FlutterロードマップFutures / Streamsでは以下の2つのサイトが紹介されています。興味のある方はぜひお読みください。

- Creating streams in Dart: https://dart.dev/articles/libraries/creating-streams
- Futures and Error handling: https://dart.dev/guides/libraries/futures-error-handling


## Future
Future（フューチャー）は、非同期処理を行うためにDart言語が提供している重要な機能です。非同期処理完了後には何らかの値またはエラーを保持します。

:::note 
非同期処理とは？？
プログラムの処理が完了してから次のプログラムを実行する（同期処理）ではなく、処理の完了を待たずに次の処理を実行すること
:::

### Futureの特徴
- 非同期処理を複数の非同期処理と並列して実行できます。これによって、非同期処理の完了を待つ間に他のタスクを実行することができます。

- 非同期処理中にエラーが発生した場合、エラー情報を取得することができるため、エラーに対する適切な処理が可能になります。

- チェーン化[^1]でき、一連の非同期操作を順次実行することができます。これによって、複雑な非同期処理の組み合わせが可能になります。

### await / async / then
Futureを使用する際、Futureの他に`await`、`async`、`then`などを使用することなります。ここではそれぞれの役割について説明します。

- **await:** awaitは非同期関数内で使用され、**Futureの結果を待つ**ために使われます。awaitが指定されたFutureが完了するまで、その非同期関数の実行は一時停止します。awaitを使用することで、非同期処理の結果を同期的に扱うことができます。
 
- **async:** asyncは非同期関数を宣言するために使用されます。asyncキーワードが関数宣言の前に置かれると、その関数は非同期であることを示します。非同期関数内でawaitを使用できます。

- **then** thenはFutureに対してチェーンで呼び出され、非同期操作が完了した後の処理を指定できます。thenを使用することで、非同期操作が完了した後に特定の処理を実行できます。

### サンプルコード

このコードは非同期処理の流れを示しており、非同期関数が他の処理をブロックせずにバックグラウンドで実行されるようになっています。

```dart: Futureサンプルコード
Future<void> fetchData() async {
  print("Fetching data...");
  // 非同期処理を模倣するためにFuture.delayedを使用
  await Future.delayed(Duration(seconds: 2));
  print("Data fetched.");
}

void main() {
  print("Start of main");

  // fetchData関数の非同期処理を開始
  fetchData().then((_) {
    print("End of main");
  });
}
```

**1. `fetchData` 関数:**
   - `async` キーワードが関数の前に付いており、これはこの関数が非同期関数であることを示しています。非同期関数は `await` を使用して非同期処理を待機できる特徴があります。
   - `await Future.delayed(Duration(seconds: 2))` の部分は、2秒間の遅延をする非同期処理です。実際のアプリケーションでは、ここでデータの取得などが行われます。

**2. `main` 関数:**
   - プログラムが実行されると、まず `print("Start of main")` が実行されて "Start of main" がコンソールに表示されます。
   - 次に `fetchData()` 関数が呼び出されます。この関数は非同期処理であるため、実際の処理が終了する前に次のコードが実行されます。
   - `fetchData()` 関数内の非同期処理が2秒後に終了すると、`.then((_) { print("End of main"); })` の部分が実行されて "End of main" がコンソールに表示されます。

## Stream
Futureは一度だけデータを取得し画面を構築するのに対して、Stream(ストリーム)は、データを監視し続け、**変化するデータによって画面を更新する**、という機能です。特に、リアルタイムのチャットアプリの実装等で役に立ちます。

### Streamの特徴
- データがストリームに流れ込むと、リスナーがこれらのデータを非同期に受信することができます。これにより、データをリアルタイムで処理できるようになります。

- 非同期操作を行うときに Stream を活用することで、データの取得、フィルタリング、変換などを非同期で行えます。

- Stream は要求に応じてバッファリング[^2]ができるため、データのバッファリングを制御し、無駄なリソース消費を防ぐことができます。

### async* / listen / yield
Streamを使用する際、Streamの他に`async*`、`listen`、`yield`などを使用することなります。ここではそれぞれの役割について説明します。

- **async***: async*は、非同期関数を定義するための修飾子です。データを逐次生成し、非同期処理中に一時停止し、制御を呼び出し元に戻すことができます。

- **listen:** listenはStreamのメソッドで、ストリームからのイベント通知を受け取るために使用されます。Streamが新しいデータを提供するたびに、指定したコールバック関数が呼び出されます。

- **yield:** yieldは関数内で使用され、データを生成するためのキーワードです。async*関数内でyieldを使用すると、関数は逐次データを生成し、途中で非同期処理を中断できます。

### サンプルコード
```dart: Streamサンプルコード
import 'dart:async';

// 非同期データを生成するStreamを作成
Stream<int> generateAsyncData() async* {
  for (int i = 1; i <= 5; i++) {
    // 1から5までの整数を非同期に生成
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

void main() {
  print("Start of main");

  // generateAsyncDataから非同期ストリームを取得
  Stream<int> dataStream = generateAsyncData();

  // ストリームのイベントをリッスン
  dataStream.listen((data) {
    print("Received data: $data");
  },
      onDone: () {
        print("End of data stream");
      });

  print("End of main");
}
```
```dart: 結果
Start of main
End of main
Received data: 1
Received data: 2
Received data: 3
Received data: 4
Received data: 5
End of data stream
```

**1. `generateAsyncData`関数:**
- `generateAsyncData`関数は、`Stream<int>`型を返す非同期関数です。この関数は`async*`キーワードを使用して、非同期で整数を生成します。forループを使用して1から5までの整数を生成し、それぞれを`yield`キーワードでストリームに提供します。整数を提供した後、`await Future.delayed`を使用して1秒間待機しています。

**2. `main 関数`:**
- `Start of main`というテキストを表示してから、非同期データ生成のために`generateAsyncData`関数を呼び出し、その結果を`dataStream`に代入します。

- `dataStream`はストリーム型で、`listen`メソッドを使用してそのイベントを監視しています。`listen`メソッドは、データがストリームから提供されるたびにコールバック関数を呼び出します。また、非同期処理が終了したときに`onDone`コールバックが呼び出されます。

- コードの実行が進むにつれ、非同期データ生成とリッスンの結果、コンソールに`Received data: x`という形式で1から5までの整数が表示され、最後に`End of data stream`が表示されます。


## 参考資料

https://zenn.dev/urasan/articles/f6613470658de1

https://blog.flutteruniv.com/flutter-future-stream-difference/

https://zenn.dev/iwaku/articles/2020-12-10-iwaku

[^1]: **チェーン化**
複数の非同期操作を順番に実行する方法です。チェーン化により、非同期処理の順序と制御を簡単に行うことができるようになります。主にthenメソッドを使用して実現されます。

[^2]: **バッファリング**
データをやり取りするときに、処理速度や転送速度の差を補ったり、通信の減速や中断に備えて専用の記憶領域に送受信データを一時的に保存しておくことです。バッファを使えば、データが届くのが遅れても、バッファが空にならない限りはやりとりが中断されることはありません。[こちら](https://wa3.i-3-i.info/word110442.html)にわかりやすい記事があったので、是非読んでみてください。