Dart Lesson 33 – Streams | Dataplexa

Streams in Dart

In this lesson, you will learn about Streams in Dart. Streams are used to handle multiple asynchronous values over time, instead of a single value like Future.

Streams are commonly used for real-time data such as user activity, sensor readings, live chat messages, and server events.


Why Streams Are Needed

A Future gives only one value. But in many real-world applications, data arrives continuously.

For example:

  • Live stock prices updating every second
  • Chat messages coming from users
  • Real-time sensor data

Streams solve this problem.


Basic Stream Example

Let’s create a stream that emits numbers every second.

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

Listening to a Stream

You can listen to stream values using listen().

void main() {
  numberStream().listen((value) {
    print("Received: $value");
  });
}

Real-World Example: Live User Count

Imagine an application that shows the number of active users in real time.

Stream activeUsers() async* {
  List users = [120, 135, 150, 142, 160];

  for (int count in users) {
    await Future.delayed(Duration(seconds: 1));
    yield count;
  }
}

Consuming the Stream

void main() {
  activeUsers().listen((count) {
    print("Active Users: $count");
  });
}

Using await for with Streams

You can use await for to process streams sequentially.

void main() async {
  await for (int value in numberStream()) {
    print("Value: $value");
  }
}

Single Subscription vs Broadcast Streams

There are two types of streams:

  • Single-subscription – listened by one listener
  • Broadcast – listened by multiple listeners

Broadcast Stream Example

Let’s convert a stream into a broadcast stream.

Stream broadcastStream() {
  return numberStream().asBroadcastStream();
}

Multiple Listeners

void main() {
  var stream = broadcastStream();

  stream.listen((value) {
    print("Listener 1: $value");
  });

  stream.listen((value) {
    print("Listener 2: $value");
  });
}

Handling Stream Errors

Streams can emit errors which should be handled properly.

Stream errorStream() async* {
  yield 1;
  yield 2;
  throw Exception("Stream error occurred");
}

Error Handling While Listening

void main() {
  errorStream().listen(
    (value) => print(value),
    onError: (error) => print("Error: $error"),
    onDone: () => print("Stream closed"),
  );
}

Stream Lifecycle

  • Stream starts emitting data
  • Listeners receive values
  • Errors may occur
  • Stream closes

Common Stream Use Cases

  • Chat applications
  • Live dashboards
  • Event-driven systems
  • IoT data streams

📝 Practice Exercises


Exercise 1

Create a stream that emits temperatures every second.

Exercise 2

Listen to a stream and print values.

Exercise 3

Convert a stream into a broadcast stream.


✅ Practice Answers


Stream temperatureStream() async* {
  List temps = [30, 31, 29, 32, 33];
  for (var t in temps) {
    await Future.delayed(Duration(seconds: 1));
    yield t;
  }
}

void main() async {
  await for (var temp in temperatureStream()) {
    print("Temperature: $temp°C");
  }
}

What’s Next?

In the next lesson, you will learn about Error Handling & Debugging in Dart, including best practices for production applications.