【Flutter】stream.periodicの使い方まとめ

Flutter基礎

flutterでテストケースを書いていて、stream.periodicを使用するシーンに出会ったので、理解を深めたく記事にしました。

periodicの使い方や理解を深めたい方の参考になれば幸いです。

前提知識

Streamとは?

そもそも Stream は何かというと、以下のように理解できます。

  • 非同期のデータの流れを表す型
  • データが「流れてくる川」のようなイメージ
  • 並行処理や非同期処理の結果を順次受け取れる仕組み

例えばチャットやセンサー値など「継続的にデータが発生する」ケースに向いています。

公式ドキュメント


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, 16
  • Duration で周期を指定
  • 第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回で自動終了するお手軽なタイマー処理」になる
  • 簡単な定期処理やテスト用途にとても便利

テストで使用するケースがあって理解を深めるためにまとめてみました。
どなたかのお役に立てると幸いです。

ではまた。

コメント

タイトルとURLをコピーしました