Menu
Coddy logo textTech

Stream Controller

CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 78/110。

async* ジェネレータは、事前に定義されたデータを使用してストリームを作成するのに適していますが、コードのさまざまな部分からストリームにデータを追加するなど、より詳細な制御が必要な場合があります。そこで StreamController の出番です。

StreamController はストリームのマネージャーとして機能します。これは、データを追加するための「sink」と、リスナーが購読できる「stream」を提供します:

import 'dart:async';

void main() {
  var controller = StreamController<String>();
  
  // ストリームをリッスンします
  controller.stream.listen((data) {
    print('Received: $data');
  });
  
  // シンク経由でデータを追加します
  controller.add('Hello');
  controller.add('World');
  
  controller.close();  // 完了したら必ずクローズしてください
}

add() メソッドは新しい値をストリームにプッシュし、リスナーはそれらを即座に受け取ります。リソースを解放するために、終了したときには常に close() を呼び出す必要があります。

デフォルトでは、ストリームは1つのリスナーしか持つことができません。複数のリスナーが必要な場合は、ブロードキャストコントローラを使用します:

import 'dart:async';

void main() {
  var controller = StreamController<int>.broadcast();
  
  controller.stream.listen((n) => print('Listener 1: $n'));
  controller.stream.listen((n) => print('Listener 2: $n'));
  
  controller.add(42);
  controller.close();
}

StreamControllersは、データの変更時にアプリの複数の部分に通知したり、ユーザーのアクションを処理したり、オブジェクト内のリアルタイム更新を管理したりするなど、イベント駆動型のクラスを構築するためにOOPにおいて不可欠です。

challenge icon

チャレンジ

簡単

複数のサブスクライバーがリアルタイムでメッセージを受信できるメッセージハブシステムを構築しましょう!StreamController を使用してメッセージの流れを管理し、ブロードキャストストリームによって複数のリスナーが可能になる仕組みを実演します。

コードを2つのファイルに分けて構成します:

  • message_hub.dart: StreamController を使用してメッセージ配信を管理する MessageHub クラスを作成します。ハブは以下の機能を備えている必要があります:
    • 複数のリスナーが購読できるように、内部でブロードキャスト StreamController<String> を使用する
    • リスナーが購読するためのストリームを返す messages というゲッターを提供する
    • ストリームにメッセージを追加する broadcast(String message) メソッドを持つ
    • コントローラーを閉じる shutdown() メソッドを持つ
  • main.dart: メッセージハブをインポートし、同じストリームをリッスンする複数のサブスクライバーを設定するシナリオを作成します:
    • MessageHub インスタンスを作成する
    • Subscriber A: [message] という形式でメッセージを出力する1つ目のリスナーを追加する
    • Subscriber B: [message] という形式でメッセージを出力する2つ目のリスナーを追加する
    • 3つのメッセージ Hello everyoneWelcome to the hubGoodbye をブロードキャストする
    • ハブをシャットダウンする

StreamController にアクセスするために、メッセージハブファイルで dart:async をインポートすることを忘れないでください。両方のサブスクライバーがブロードキャストされたすべてのメッセージを受信することに注目してください。これがブロードキャストストリームの強力な点です!

期待される出力:

Subscriber A: Hello everyone
Subscriber B: Hello everyone
Subscriber A: Welcome to the hub
Subscriber B: Welcome to the hub
Subscriber A: Goodbye
Subscriber B: Goodbye

チートシート

StreamControllerはストリームを管理し、つ、どのようにデータが追加されるかを制御します。データを追加するための「sink」と、リスナーが購読できる「stream」を提供します。

基本的な使い方:

import 'dart:async';

var controller = StreamController<String>();

// Listen to the stream
controller.stream.listen((data) {
  print('Received: $data');
});

// Add data through the sink
controller.add('Hello');
controller.add('World');

controller.close();  // Always close when done

add()メソッドは、新しい値をストリームにプッシュします。リスナーはそれらを即座に受け取ります。リソースを解放するために、終了時には必ずclose()を呼び出してください。

デフォルトでは、ストリームは1つのリスナーしか持つことができません。複数のリスナーが必要な場合は、ブロードキャストコントローラーを使用します:

var controller = StreamController<int>.broadcast();

controller.stream.listen((n) => print('Listener 1: $n'));
controller.stream.listen((n) => print('Listener 2: $n'));

controller.add(42);
controller.close();

StreamControllerは、イベント駆動型のクラスの構築、データ変更時のアプリの複数箇所への通知、ユーザーアクションの処理、またはリアルタイム更新の管理に不可欠です。

自分で試してみよう

import 'message_hub.dart';

void main() {
  // TODO: MessageHub インスタンスを作成する
  
  // TODO: 「Subscriber A: [message]」と出力する最初のリスナーを追加する
  
  // TODO: 「Subscriber B: [message]」と出力する2番目のリスナーを追加する
  
  // TODO: 3つのメッセージをブロードキャストする:
  // - "Hello everyone"
  // - "Welcome to the hub"
  // - "Goodbye"
  
  // TODO: ハブをシャットダウンする
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン