Un Stream es una secuencia de eventos asincrónicos . Es como un Iterable asíncrono, donde, en lugar de obtener el siguiente evento cuando lo solicita, la secuencia le dice que hay un evento cuando está listo.
En otras palabras, los flujos son una fuente de eventos asincrónicos entregados secuencialmente. Hay eventos de datos, a los que a veces se hace referencia como elementos de la secuencia debido a la similitud de la secuencia con una lista, y hay eventos de error, que son notificaciones de fallas. Una vez que se hayan emitido todos los elementos de datos, un evento especial que indica que la transmisión ha finalizado notificará a los oyentes que no hay más.
Ventaja de corrientes:
La principal ventaja de usar flujos para comunicarse es que mantiene el código acoplado de forma flexible. El propietario de una transmisión puede emitir valores a medida que estén disponibles y no necesita saber nada sobre quién está escuchando o por qué. De manera similar, los consumidores de los datos solo necesitan adherirse a la interfaz del flujo, y los medios por los cuales se generan los datos del flujo están completamente ocultos.
Puntos para recordar:
- Una transmisión es como una tubería, pones un valor en un extremo, y si hay un oyente en el otro extremo, ese oyente recibirá ese valor.
- Puede procesar una transmisión usando esperar o escuchar() desde la API de transmisión.
¿Cómo se crean los flujos?
Los flujos se pueden crear de muchas maneras: la espera asincrónica itera sobre los eventos de un flujo, como el ciclo for itera sobre un iterable.
Ejemplo 1:
Dart
Future<int> sumStream(Stream<int> stream) async { var sum=0; await for(var value in stream) { sum += value; } return sum; } Future<void> main() async { final stream = Stream<int>.fromIterable([1,2,3,4,5]); final sum = await sumStream(stream); print('Sum: $sum'); }
Producción:
Explicación: este código simplemente recibe cada evento de un flujo de eventos enteros, los suma y devuelve (un futuro de) la suma. Cuando finaliza el cuerpo del ciclo, la función se detiene hasta que llega el siguiente evento o se completa la transmisión.
En función, hemos usado la palabra clave async , que se requiere cuando se usa await para un bucle.
Conceptos importantes de Streams en Flutter:
Stream Controller: un StreamController simplifica la gestión de flujos, crea automáticamente un flujo y un sumidero y proporciona métodos para controlar el comportamiento de un flujo. Un objeto StreamController en Dart hace exactamente lo que sugiere el nombre, controla Dart Streams. El objeto se utiliza para crear flujos y enviar datos , errores y eventos realizados en ellos. Los controladores también ayudan a verificar las propiedades de una transmisión, como cuántos suscriptores tiene o si está en pausa.
Stream Builders: StreamBuilder es un widget que usa operaciones de transmisión y, básicamente, reconstruye su interfaz de usuario cuando obtiene los nuevos valores que se pasan a través de Stream que escucha.
StreamBuilder requiere 2 parámetros:
- flujo: un método que devuelve un objeto de flujo
- builder: widgets que se devolverán durante diferentes estados de un streambuilder .
Implementación práctica de Stream Controller y Stream builder utilizando la aplicación Countdown:
Crearemos una aplicación de cuenta regresiva Flutter usando Stream Controller y Stream builder . En este ejemplo de Flutter StreamController, simplemente crearemos una aplicación que puede contar un valor de n a 0 utilizando el receptor de flujo del controlador y actualizar la interfaz de usuario.
ejemplo 1: main.dart
Dart
import 'dart:async'; import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: CounterApp() ); } } class CounterApp extends StatefulWidget { const CounterApp({Key? key}) : super(key: key); @override _CounterAppState createState() => _CounterAppState(); } class _CounterAppState extends State<CounterApp> { // create instance of streamcontroller class StreamController _controller = StreamController(); int _counter = 10; void StartTimer() async{ // Timer Method that runs every second Timer.periodic(Duration(seconds: 1), (timer) { _counter--; // add event/data to stream controller using sink _controller.sink.add(_counter); // will stop Count Down Timer when _counter value is 0 if(_counter<=0){ timer.cancel(); _controller.close(); } }); } @override void dispose() { super.dispose(); // Destroy the Stream Controller when use exit the app _controller.close(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ StreamBuilder( initialData: _counter, stream: _controller.stream, builder: (context,snapshot){ return Text('${snapshot.data}'); } ), SizedBox( height: 20, ), ElevatedButton(onPressed: (){ // start the timer StartTimer(); }, child: Text('Start Count Down')) ], ), ), ); } }
Producción:
Explicación:
Hay dos puntos importantes a saber:
- Sumidero: en Flutter Streams, un Sumidero es un punto desde donde podemos agregar datos a la tubería de flujo.
- Fuente : en Flutter Stream, una fuente es un punto desde donde podemos seguir escuchando los datos de la transmisión u obtener los datos que se agregaron a la transmisión.
En el código anterior, hemos creado StreamController y le agregamos datos usando sink.add().
Podemos ver a continuación cómo usamos el controlador de flujo en el código anterior:
// Create Stream StreamController _controller = StreamController(); int _counter = 60; // add event/data to stream controller using sink _controller.sink.add(_counter);
Aquí ponemos el conteo inicial en 10. Entonces, desde 10, irá en orden inverso hasta que el valor llegue a 0.
Ahora necesitamos escuchar los datos que ingresan a la transmisión e imprimir los datos en la pantalla, por lo que usamos el widget StreamBuilder para escuchar el evento asíncrono.
A continuación se muestra un pseudocódigo que muestra cómo usamos stream builder en el programa anterior para recopilar datos e imprimirlos en la pantalla:
StreamBuilder( initialData: _counter, stream: _controller.stream, builder: (context,snapshot){ return Text('${snapshot.data}'); } )
Dos tipos de flujos:
- Flujos de suscripción única
- Transmisión de transmisiones
1. Flujos de suscripción única:
Las secuencias de suscripción única son las predeterminadas. Funcionan bien cuando solo usas una transmisión en particular en una pantalla.
Una sola transmisión de suscripción solo se puede escuchar una vez. No comienza a generar eventos hasta que tiene un oyente y deja de enviar eventos cuando el oyente deja de escuchar, incluso si la fuente de los eventos aún podría proporcionar más datos.
Las secuencias de suscripción única son útiles para descargar un archivo o para cualquier operación de un solo uso. Por ejemplo, un widget puede suscribirse a una secuencia para recibir actualizaciones sobre un valor, como el progreso de una descarga, y actualizar su interfaz de usuario en consecuencia.
Ejemplo 1.
Dart
import 'dart:convert'; import 'dart:async'; // Initializing a stream controller StreamController<String> controller = StreamController<String>(); // Creating a new stream through the controller Stream<String> stream = controller.stream; void main() { // Setting up a subscriber to listen for any events sent on the stream StreamSubscription<String> subscriber = stream.listen((String data) { print(data); }, onError: (error) { print(error); }, onDone: () { print('Stream closed!'); }); // Adding a data event to the stream with the controller controller.sink.add('GeeksforGeeks!'); // Adding an error event to the stream with the controller controller.addError('Error!'); // Closing the stream with the controller controller.close(); }
Producción:
2. Transmisión de transmisiones:
Si necesita varias partes de su aplicación para acceder a la misma transmisión, use una transmisión de transmisión en su lugar. Un flujo de difusión permite cualquier número de oyentes. Se dispara cuando sus eventos están listos, ya sea que haya oyentes o no. Para crear una transmisión de transmisión, simplemente llame a asBroadcastStream() en una transmisión de suscripción única existente.
Syntax: final broadcastStream = singleStream.asBroadcastStream();
Ejemplo 2.
Dart
import 'dart:convert'; import 'dart:async'; // Initializing a stream controller for a broadcast stream StreamController<String> controller = StreamController<String>.broadcast(); // Creating a new broadcast stream through the controller Stream<String> stream = controller.stream; void main() { // Setting up a subscriber to listen for any events sent on the stream StreamSubscription<String> subscriber1 = stream.listen((String data) { print('Subscriber1: ${data}'); }, onError: (error) { print('Subscriber1: ${error}'); }, onDone: () { print('Subscriber1: Stream closed!'); }); // Setting up another subscriber to listen for any events sent on the stream StreamSubscription<String> subscriber2 = stream.listen((String data) { print('Subscriber2: ${data}'); }, onError: (error) { print('Subscriber2: ${error}'); }, onDone: () { print('Subscriber2: Stream closed!'); }); // Adding a data event to the stream with the controller controller.sink.add('GeeksforGeeks!'); // Adding an error event to the stream with the controller controller.addError('Error!'); // Closing the stream with the controller controller.close(); }
Producción :
Veamos algunos de los métodos útiles de las clases que se utilizan en los programas anteriores:
- método add(): maneja el reenvío de cualquier dato al sumidero.
- Método addError(): si se produce un error y es necesario informar a los oyentes de su transmisión, se utiliza addError() .
- Método listen(): escuchamos la transmisión de datos entrantes con el método .listen() .
Publicación traducida automáticamente
Artículo escrito por ayurishchandnacs18 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA