Dart streams. An introduction with examples.

Image for post
Image for post
picture by https://pixabay.com/users/cowins-822708/

What is a Stream?

Build a stream (the manual way)

Stream<int> numberStream(int countTo) async* {
for (int i = 1; i <= countTo; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}

Listening to your stream’s events

Image for post
Image for post
image by https://pixabay.com/users/couleur-1195798/
numberStream(3).listen((event) => print("received $event"));
received 1
received 2
received 3
Stream<int> numberStream(int countTo) async* {
for (int i = 1; i <= countTo; i++) {
await Future.delayed(Duration(seconds: 1));
print("yielding $i");
yield i;
}
}
void main() {
var stream = numberStream(3);
print("stream created. Just sitting here doing nothing for a sec");
Future.delayed(Duration(seconds: 1));
stream.listen((event) => print("received $event"));
}
stream created. Just sitting here doing nothing for a second
yielding 1
received 1
yielding 2
received 2
yielding 3
received 3

listen() vs await for

stream.listen((event) => print("received $event"));
await for (var event in stream) {
print("received $event");
}
print("start");
numberStream(3).listen((event) => print("received $event"));
print("end");
start
end
received 1
received 2
received 3
print("start");
await for (var event in numberStream(3)) {
print("received $event");
}
print("end");
start
received 1
received 2
received 3
end

StreamController — the preferred way to interact with streams

Image for post
Image for post
Image by https://pixabay.com/users/niekverlaan-80788/
final subscription = numberStream(8)
.listen((event) => print("received $event"));

await Future.delayed(Duration(seconds: 3));

print("pausing the subscription and idling for 2 seconds");
subscription.pause();

await Future.delayed(Duration(seconds: 2));

print("resuming...");
subscription.resume();
await Future.delayed(Duration(seconds: 2));

print("stopping the stream");
subscription.cancel();
received 1
received 2
pausing the subscription and idling for 2 seconds
resuming...
received 3
received 4
stopping the stream

Creating a stream with StreamController

Stream<int> numberStreamWithController(int countTo) {
final controller = StreamController<int>();
var timer = null;
var counter = 0;

void count(_) {
controller.add(counter);
if (counter == countTo) {
timer.cancel();
}
counter++;
}

timer = Timer.periodic(Duration(milliseconds: 1000), count);
timer.tick;
return controller.stream;
}

Stream’s state change callbacks

When the Stream is done — listening and notifying

Warning — don’t start the stream yourself!

Error handling

Image for post
Image for post
Image by https://pixabay.com/users/aitoff-388338/

Handling errors via try/catch

if (counter == 1) {
controller.addError("Boom!");
}
try {
await for (var value in numberStreamWithController(2)) {
print("received = $value");
}
} catch (error) {
print("error = $error");
}
starting the Stream
received = 0
stopping the Stream
error = Boom!

Handling erros via .listen()

numberStreamWithController(2).listen((int value) {
print("received = $value");
}, onError: (error) {
print("error = $error");
});
starting the Stream
received = 0
error = Boom!
received = 1
received = 2

Not stopping when you get an error

Intercepting specific error events

if (counter == 3) {
controller.addError(42);
}
numberStreamWithController(3)
.handleError((e) => print("int error = $e"),
test: (e) => e is int)
.handleError((e) => print("String error = $e"),
test: (e) => e is String)
.listen((int value) {
print("received = $value");
});
starting the Stream
received = 0
String error = Boom!
received = 1
received = 2
int error = 42
received = 3

Broadcast streams. Allowing multiple subscribers.

Image for post
Image for post
Image by https://pixabay.com/users/wikiimages-1897/
final stream = manualNumberStream(5).asBroadcastStream();

stream.listen((event) {
print("1st subscriber = $event");
});

await Future.delayed(Duration(seconds: 3));

stream.listen((event) {
print("2nd subscriber = $event");
});
1st subsriber = 1
1st subsriber = 2
1st subsriber = 3
2nd subsriber = 3
1st subsriber = 4
2nd subsriber = 4
1st subsriber = 5
2nd subsriber = 5

Conclusion

Written by

Software engineer. Learning everyday and trying to share my knowledge in the process. Into mobile development, computer science and the brain.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store