Menu
Coddy logo textTech

Stream Controllers

Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 78 de 110.

Si bien los generadores async* son excelentes para crear streams con datos predefinidos, a veces necesitas más control, como añadir datos a un stream desde diferentes partes de tu código. Ahí es donde entra en juego StreamController.

Un StreamController actúa como un gestor para un stream. Te proporciona un "sink" para añadir datos y un "stream" al que los suscriptores pueden suscribirse:

import 'dart:async';

void main() {
  var controller = StreamController<String>();
  
  // Escuchar el stream
  controller.stream.listen((data) {
    print('Received: $data');
  });
  
  // Agregar datos a través del sink
  controller.add('Hello');
  controller.add('World');
  
  controller.close();  // Cerrar siempre al terminar
}

El método add() inserta nuevos valores en el flujo, y cualquier escucha los recibe inmediatamente. Siempre debes llamar a close() cuando hayas terminado para liberar recursos.

Por defecto, un stream solo puede tener un listener. Para múltiples listeners, usa un broadcast controller:

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();
}

Los StreamControllers son esenciales en la POO para construir clases orientadas a eventos, como notificar a múltiples partes de su aplicación cuando los datos cambian, manejar acciones del usuario o gestionar actualizaciones en tiempo real dentro de sus objetos.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de centro de mensajes que permita a múltiples suscriptores recibir mensajes en tiempo real! Utilizarás un StreamController para gestionar el flujo de mensajes y demostrar cómo los flujos de difusión (broadcast streams) permiten múltiples oyentes.

Organizarás tu código en dos archivos:

  • message_hub.dart: Crea una clase MessageHub que gestione la distribución de mensajes utilizando un StreamController. Tu centro debe:
    • Usar un StreamController<String> de tipo broadcast internamente para que múltiples oyentes puedan suscribirse
    • Proporcionar un getter llamado messages que devuelva el flujo para que los oyentes se suscriban
    • Tener un método broadcast(String message) que añada un mensaje al flujo
    • Tener un método shutdown() que cierre el controlador
  • main.dart: Importa tu centro de mensajes y configura un escenario con múltiples suscriptores escuchando el mismo flujo:
    • Crea una instancia de MessageHub
    • Añade un primer oyente que imprima los mensajes en el formato: Subscriber A: [message]
    • Añade un segundo oyente que imprima los mensajes en el formato: Subscriber B: [message]
    • Transmite tres mensajes: Hello everyone, Welcome to the hub, y Goodbye
    • Cierra el centro de mensajes

Recuerda importar dart:async en tu archivo del centro de mensajes para acceder a StreamController. Observa cómo ambos suscriptores reciben cada mensaje que se transmite: ¡ese es el poder de los flujos de difusión!

Salida esperada:

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

Hoja de referencia

Un StreamController gestiona un stream, proporcionando control sobre cuándo y cómo se añaden los datos. Te ofrece un "sink" para añadir datos y un "stream" al que los oyentes pueden suscribirse.

Uso básico:

import 'dart:async';

var controller = StreamController<String>();

// Escuchar el stream
controller.stream.listen((data) {
  print('Received: $data');
});

// Añadir datos a través del sink
controller.add('Hello');
controller.add('World');

controller.close();  // Cerrar siempre al terminar

El método add() envía nuevos valores al stream. Los oyentes los reciben inmediatamente. Llama siempre a close() cuando hayas terminado para liberar recursos.

Por defecto, un stream solo puede tener un oyente. Para múltiples oyentes, utiliza un controlador de difusión (broadcast controller):

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();

Los StreamControllers son esenciales para construir clases orientadas a eventos, notificar a múltiples partes de tu aplicación cuando los datos cambian, manejar acciones del usuario o gestionar actualizaciones en tiempo real.

Pruébalo tú mismo

import 'message_hub.dart';

void main() {
  // TODO: Crea una instancia de MessageHub
  
  // TODO: Añade el primer listener que imprima: Subscriber A: [message]
  
  // TODO: Añade el segundo listener que imprima: Subscriber B: [message]
  
  // TODO: Transmite tres mensajes:
  // - "Hello everyone"
  // - "Welcome to the hub"
  // - "Goodbye"
  
  // TODO: Cierra el hub
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos