Lesson 17 / 25
Streams
Consume and create streams of asynchronous events.
Many values over time
A Stream<T> delivers a sequence of asynchronous events: user input, WebSocket messages, file chunks, database change notifications, location updates. Consume a stream with await for inside an async function, or with listen, which returns a StreamSubscription you can pause, resume and cancel (always cancel subscriptions you no longer need to avoid leaks, for example in a Flutter widget's dispose). Single-subscription streams (the default, such as reading a file) allow one listener; broadcast streams allow many listeners and suit events such as UI notifications. Streams have collection-like operators: map, where, take, skip, distinct, asyncMap, expand and handleError. Create streams with async* generator functions that yield values, or with a StreamController that you add events to, close when finished, and expose via its stream property. Packages such as rxdart add more operators, and Flutter's StreamBuilder rebuilds widgets as events arrive.
A stream generator, a controller and await for
async* yields values over time; controllers bridge callback code.
import 'dart:async';
Stream<int> countdown(int from) async* {
for (var i = from; i >= 0; i--) {
await Future<void>.delayed(const Duration(seconds: 1));
yield i; // emit the next value
}
}
class CartEvents {
final _controller = StreamController<String>.broadcast();
Stream<String> get stream => _controller.stream;
void itemAdded(String sku) => _controller.add('added $sku');
Future<void> dispose() => _controller.close();
}
Future<void> main() async {
await for (final seconds in countdown(3)) {
print('Sale starts in $seconds');
}
final events = CartEvents();
final subscription = events.stream
.where((e) => e.startsWith('added'))
.listen((e) => print('Event: $e'));
events.itemAdded('pen');
events.itemAdded('ink');
await Future<void>.delayed(Duration.zero); // let events be delivered
await subscription.cancel(); // always cancel when done
await events.dispose();
}A newspaper subscription
A Future is a single parcel you are waiting for. A Stream is a newspaper subscription: issues keep arriving until the publisher stops, and you should cancel the subscription when you move away.
Quick check: What does an async* function return?
- A Future
- A Stream, emitting values with yield
- A List
- An Isolate
Answer
A Stream, emitting values with yield — async* generators produce streams; sync* generators produce iterables.