📦
【Flutter】Streamの概念の理解と基本的な使い方
Streamを初めて使う方に向けたブログです。非同期処理やリアクティブなUI更新に興味はあるけれど、Streamって何?どう使うの?という方に、概念から基本的な使い方まで、分かりやすく解説します。
この記事で学べること
- Streamの概念
- データの流し方
- UIをリアクティブに描画する
Streamの概念をイメージで掴む
まずは、この絵を見てください

Streamは『川』、データは『荷物』だと思ってください
川に荷物を流すと、下流で受け取れますよね?
Flutterでは、この受け取った荷物を使ってUIを更新します
このシンプルなイメージを持って、以下の基本的な使い方を見ていきましょう
基本的な使い方
シンプルなカウンターアプリをStreamを使用して実装してみます
データの流し方
まずはStreamを定義
final _counterStreamController = StreamController<int>();
FloatingActionButton押下した時にデータをStreamに流す
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Stream')),
body: Center(...),
floatingActionButton: FloatingActionButton(
onPressed: onTapPlusButton,
child: Icon(Icons.add),
),
);
}
void onTapPlusButton() {
_counter++;
// 以下2つともやってることは同じ
// 明示的に書き込みと表しているのは「sink」の方
_counterStreamController.add(_counter);
}
UIをリアクティブに描画する
Streamを購読し、データが流れてきたら描画更新されるStreamBuilderを使う
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Stream')),
body: Center(
// StreamBuilderのstreamに購読したいStreamを指定する
child: StreamBuilder(
stream: _counterStreamController.stream,
builder: (context, snapshot) {
// データの有無をsnapshot.hasDataで確認し、それぞれの描画を実装できる
if (snapshot.hasData) {
// データがあればカウントした数を描画
return Text('カウント: ${snapshot.data}');
} else {
// データがまだ流れてきてなければ、ローディング表示
return CircularProgressIndicator();
}
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: onTapPlusButton,
child: Icon(Icons.add),
),
);
}
Streamの破棄
適切に破棄しないとメモリリークが起こる可能性があるため、close()を呼び出しStreamControllerを破棄します
void dispose() {
// 画面のDispose時にStreamを破棄する
_counterStreamController.close();
super.dispose();
}
まとめ
今回は、Streamの概念から基本的な使い方までを、初心者向けに解説しました
Streamは「川」、データは「荷物」というイメージで理解すると分かりやすい
StreamControllerでデータを流し、StreamBuilderでUIをリアクティブに更新できる
dispose()で必ずclose()を呼び、リソースを適切に破棄することが重要
この基本を押さえれば、非同期処理やリアクティブUIの第一歩を踏み出せます。
次は、BlocパターンやRiverpodのStreamProviderなど、より実践的なアプローチに挑戦してみましょう
Discussion