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.