Stream în Dart

Un șir de valori care sosesc în timp, una după alta (mesaje, clicuri, linii dintr-un fișier); îl parcurgi cu await for.

Sintaxă
abstract mixin class Stream<T>

await for (final x in stream) { ... }
Stream<T> functie() async* { yield valoare; }

Ce face Stream

Dacă un Future este o singură valoare care vine mai târziu, un Stream<T> este o succesiune de valori care vin pe rând, urmate eventual de un semnal de final („done”). Pe lângă valori, un stream poate emite și erori.

Cel mai simplu îl parcurgi cu await for, într-o funcție async: bucla primește fiecare valoare când sosește și se termină când stream-ul se închide. Poți crea un stream cu o funcție async* care face yield, cu constructori ca Stream.fromIterable sau cu un StreamController.

Stream-urile obișnuite („single-subscription”) pot fi ascultate o singură dată. Ca la Iterable, ai map, where, take și altele, care returnează stream-uri noi, plus metode ca toList sau first, care returnează un Future.

Ce returnează

Un obiect Stream<T>; valorile lui se primesc prin await for sau listen.

Exemple

Exemplul 1: Un stream creat cu async* și citit cu await for

Stream<int> numaratoare(int de) async* {
  for (var i = de; i > 0; i--) {
    await Future.delayed(const Duration(milliseconds: 50));
    yield i;
  }
}

Future<void> main() async {
  await for (final n in numaratoare(3)) {
    print('$n...');
  }
  print('Lansare!');
}

Rezultat

3...
2...
1...
Lansare!

Exemplul 2: Transformări în lanț

Future<void> main() async {
  final temperaturi = Stream.fromIterable([18, 25, 31, 22, 34, 29]);
  final caniculare = temperaturi.where((t) => t >= 30).map((t) => '$t °C');
  print(await caniculare.toList());
}

Rezultat

[31 °C, 34 °C]

Exemplul 3: Un stream obișnuit se ascultă o singură dată

Future<void> main() async {
  final s = Stream.fromIterable(['Ana', 'Mihai']);
  print(await s.toList());
  try {
    await s.toList();
  } on StateError catch (e) {
    print('A doua ascultare: ${e.message}');
  }
}

Rezultat

[Ana, Mihai]

Greșeli frecvente

  • Asculți de două ori același stream obișnuit. Apare StateError: Stream has already been listened to; folosește un stream broadcast sau asBroadcastStream.
  • Folosești await for pe un stream care nu se închide niciodată (de exemplu Stream.periodic). Bucla nu se termină; limitează-l cu take.

Comenzi înrudite

  • Stream.listen: Începe ascultarea unui stream: o funcție pentru fiecare valoare, una pentru erori, una pentru final.
  • await for: Parcurge un Stream element cu element, așteptând fiecare eveniment; se termină când stream-ul se închide.
  • async*: O funcție async* produce un Stream: trimite valori cu yield, în timp, și poate folosi await între ele.
  • StreamController: Creează un stream pe care îl alimentezi tu: ce pui cu add ajunge la cei care ascultă controller.stream.
  • Future: O valoare care va fi gata mai târziu (citirea unui fișier, un răspuns de la server); o aștepți cu await.
  • Stream.fromIterable: Creează un stream care emite, pe rând, elementele unei liste sau ale altui Iterable, apoi se închide.