flutterでテストケースを書いていて、stream.periodicを使用するシーンに出会ったので、理解を深めたく記事にしました。
periodicの使い方や理解を深めたい方の参考になれば幸いです。
前提知識
Streamとは?
そもそも Stream は何かというと、以下のように理解できます。
- 非同期のデータの流れを表す型
- データが「流れてくる川」のようなイメージ
- 並行処理や非同期処理の結果を順次受け取れる仕組み
例えばチャットやセンサー値など「継続的にデータが発生する」ケースに向いています。
公式ドキュメント
- Dart公式: Using streams
- Flutter API: Stream.periodic
Stream.periodicとは?
英単語の意味
periodic = 「周期的な」「定期的な」「断続的な」
その名の通り「一定間隔で繰り返しイベントを発行するStream」を生成できます。
基本の使い方
final stream = Stream<int>.periodic(
const Duration(seconds: 1),
(count) => count * count, // countは0からインクリメントされる
).take(5);
stream.forEach(print);
// 出力: 0, 1, 4, 9, 16Durationで周期を指定- 第2引数
(count)は「0から始まるインデックス」 - 返り値がそのままイベントとして流れる
.take について
.take(n) は、先頭から n 件のイベントだけを受け取るためのメソッドです。
IterableにもStreamにも共通して利用可能- メリット
- 指定回数で自動的に終了するので
cancel()を書く必要がない - サンプル実装やテストで「とりあえず何件か流す」用途に便利
- 指定回数で自動的に終了するので
参考例
- 1秒ごとに「現在時刻」を5回だけ出力する例
final stream =
Stream.periodic(const Duration(seconds: 1), (_) => DateTime.now())
.take(5);
出力用ボタン
ElevatedButton(
onPressed: () {
stream.listen((event) {
print(event);
});
},
child: Text('ボタン'),
)出力例:
2025-09-11 16:00:01.234
2025-09-11 16:00:02.235
2025-09-11 16:00:03.236
...テストで使用する場合の例
単体テストでも使用するケースがあると思うので例を記載します。
全体
testWidgets('ローディング状態ならインジケータを表示', (tester) async {
await tester.pumpWidget(ProviderScope(
overrides: [
// ローディング状態を模擬
// わざと、データがきていない状態(Loading)を再現
authStateProvider.overrideWith((ref) => Stream<UserEntity?>.periodic(
const Duration(milliseconds: 10), (count) => null).take(1)),
],
child: const MaterialApp(home: App()),
));
// emit前のローディング状態で確認
await tester.pump(const Duration(milliseconds: 100));
expect(find.byType(CircularProgressIndicator), findsOneWidget);
await tester.pumpAndSettle(); // periodicのTimerを消化して安全にテスト終了
});periodicの使い方
こちらのケースでは、下記のような意図があります。
- authStateProviderというStreamProviderに対してデータが流れてくる前の「loading状態」をテストしたい。
上記の意図に対して
periodicを使うことで「わざと遅れてイベントが発行される状況」を簡単に作れる。pump(const Duration(milliseconds: 100))で十分な時間待機 → 最初の emit 前の状態を確認。pumpAndSettle()でTimerを消化 → 残タスクを全部流してからテスト終了。
としています。「10ms後に1回だけnullをemitするストリーム」を作って、emit前の loading 状態をテストを実行する形にしています。
まとめ
まとめると下記のような理解になります。
Stream.periodicは「一定周期でイベントを発行するStream」を作れる.take(n)を組み合わせれば「n回で自動終了するお手軽なタイマー処理」になる- 簡単な定期処理やテスト用途にとても便利
テストで使用するケースがあって理解を深めるためにまとめてみました。
どなたかのお役に立てると幸いです。
ではまた。



コメント