Ir al contenido

Guía de Flutter para novatos - Miguel Páramos

FAQ sobre Flutter pal que no tiene ni idea de Flutter | 2º DAM · PMDM

Qué es un Stream en Dart y cómo suscribirse y cancelar en initState() y dispose()

En Dart y Flutter, el concepto de Stream es fundamental para trabajar con programación reactiva y fuentes continuas de datos asíncronos. Para quienes vienen de Android con Kotlin, un Stream es el equivalente directo a un Flow de Kotlin Coroutines o a un Observable en RxJava.

  • Un Future en Dart es análogo a una llamada suspend fun: ejecuta una tarea asíncrona, entrega un único resultado (o error) y finaliza.
  • Un Stream es una tubería de flujo continuo que emite múltiples datos o eventos a lo largo del tiempo.

Ejemplos habituales de uso de Streams:

  • Un socket de mensajería o chat en tiempo real (cada nuevo mensaje recibido es un evento emitido por el stream).
  • El sensor GPS del dispositivo móvil (emite una nueva coordenada geográfica periódicamente).
  • Datos telemétricos de sensores de hardware (acelerómetro, giroscopio, podómetro).
  • Actualizaciones en tiempo real procedentes de bases de datos reactivas (como Firebase Firestore o Supabase).

Gestión del ciclo de vida: Suscribirse en initState() y cancelar en dispose()

Sección titulada «Gestión del ciclo de vida: Suscribirse en initState() y cancelar en dispose()»

Cuando nos suscribimos manualmente a un Stream dentro de un StatefulWidget, es imprescindible gestionar su ciclo de vida para evitar fugas de memoria (memory leaks):

class _SensorState extends State<MiSensor> { // Clase de estado mutable del sensor
StreamSubscription? _suscripcion; // Referencia a la suscripción para poder cancelarla luego
@override // Evento de ciclo de vida: creación inicial del widget
void initState() { // Se ejecuta una sola vez al nacer el widget
super.initState(); // Llamada obligatoria al método de la clase padre
_suscripcion = sensorGps.stream.listen((posicion) { // Se suscribe al flujo reactivo continuo
print('Nueva posición recibida: $posicion'); // Procesa cada coordenada emitida por el sensor
}); // Fin del listener
} // Fin de initState
@override // Evento de ciclo de vida: destrucción final del widget
void dispose() { // Se ejecuta al salir definitivamente de pantalla
_suscripcion?.cancel(); // Cancela la suscripción para evitar fugas de memoria
super.dispose(); // Llamada obligatoria a la liberación del padre
} // Fin de dispose
} // Fin de la clase _SensorState