Cover Image

Streams in Dart | Dart Asynchronous Programming

Madhavam Pratap Shahi
3 min readAug 1, 2021

--

This is the second part of my asynchronous programming with Dart series, I highly recommend you to first read the previous parts to get a better understanding of the concepts.

Let’s get started!

The Definition :-

“In computer science, a stream is a sequence of data elements made available over time. A stream can be thought of as items on a conveyor belt being processed one at a time rather than in large batches.”

Why use Streams?

  • Streams provide an asynchronous sequence of data.
  • You can process a stream using either await for or listen() from the Stream API.
  • Data sequences include user-generated events and data read from files.
  • Streams provide an easy way to respond to errors.

“Futures” provide a single value asynchronously while Streams provide a sequence of values asynchronously over time.

In software development, we use streams very often as the modern applications are highly asynchronous, anything can happen at anytime, we always have a lot of network calls, file I/O & so much more operations which require us to use streams.

Generating a stream in Dart :-

Stream<int> counterStream() async* {//notice the asterisk
for (int i = 1; i <= 5; i++) {
yield i;
// with streams we use the "yield" keyword (similar to "return" keyword )
}
}

The above code yields an integer when called; Let’s see how it works.

void main(){

Stream str=counterStream();

str.listen((e)=>print(e));//listening to the events(generated by yield)
}
//Output:-
1
2
3
4
5

Receiving a Stream in Dart :-

To receive stream events we use the “await for” keyword.

For example,

Future<int> sumS(Stream<int> stream) async {
var sum = 0;
await for (var value in stream) { //notice the "await for"
sum += value;
}
return sum;
}

Error events :-

In some cases, an error happens before the stream is done; it could be a network error, a bug or something other, in those cases we must return an error event so that we can handle those events accordingly.

For example;

Stream<int> counterStream() async* {
for (int i = 1; i <= 5; i++) {
if (i == 4) {
throw Exception('Some error occured');//returns an error event
} else {
yield i;
}
}
}

Kinds of streams :-

Single subscription streams

The most common kind of stream contains a sequence of events that are parts of a larger whole. Events need to be delivered in the correct order and without missing any of them. This is the kind of stream we get when we read a file or receive a web request.

Such a stream can only be listened to once. Listening again later could mean missing out on initial events, and then the rest of the stream holds no value. When we start listening, the data will be fetched and provided in chunks.

Broadcast streams

The other kind of stream is intended for individual messages that can be handled one at a time.

You can start listening to such a stream at any time, and you get the events that are fired while you listen. More than one listener can listen at the same time, and you can listen again later after canceling a previous subscription.

Important: In Dart, by default, streams are single subscription. They hold onto their values until someone subscribes, and they only allow a single listener for their entire lifespan. If you try to listen to a stream twice, you’ll get an exception.

But Dart also offers broadcast streams. You can use the asBroadcastStream() method to make a broadcast stream from a single subscription stream. Broadcast streams can have multiple listeners, and if nobody’s listening when a piece of data is ready, that data is tossed out.

Example,

final myStream = singleSub.asBroadcastStream();

That’s it, that covers almost every aspect of using Streams in Dart.

Hope it was helpful in understanding streams.

Stay Tuned for more!

--

--

Madhavam Pratap Shahi

Full-stack software developer 💫❤️| I love good code❤️