Using Streams for Asynchronous Data in Dart
Streams in Dart provide a way to handle asynchronous data sequences. They allow you to work with a series of events or data over time, making them ideal for scenarios like user input, web socket events, and data from APIs. Streams can be thought of as a pipeline of data that can be listened to and processed as new data arrives.
Key Concepts
What is a Stream?
A Stream
is a sequence of asynchronous events. You can listen to a stream to receive data as it becomes available, rather than waiting for all the data to be ready at once.
Types of Streams
- Single-Subscription Stream: A stream that can be listened to only once. It's typically used for operations where a single sequence of data is expected.
- Broadcast Stream: A stream that can have multiple listeners. It allows multiple subscribers to receive the same events.
Creating a Stream
You can create a stream using the Stream
class, either by using a generator function or by using a stream controller.
Example of Creating a Stream
Stream<int> countStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1)); // Simulating asynchronous work
yield i; // Yielding values to the stream
}
}
Listening to a Stream
To receive data from a stream, you need to listen to it. You can use the listen
method to handle incoming data.
Example of Listening to a Stream
void main() {
print('Counting...');
countStream().listen((data) {
print(data); // Output: 1, 2, 3, 4, 5 (one per second) });
}
Using Async and Await with Streams
You can also use await for
to listen to a stream asynchronously. This allows you to process events as they arrive.
Example of Using Async and Await
Future<void> main() async {
print('Counting...');
await for (var data in countStream()) {
print(data); // Output: 1, 2, 3, 4, 5 (one per second) }
}
Handling Errors in Streams
Streams can produce errors in addition to data. You can handle errors by providing an onError
callback in the listen
method.
Example of Error Handling in Streams
Stream<int> errorStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
if (i == 3) {
throw Exception('Error at value 3');
}
yield i;
}
}
Future<void> main() async {
print('Counting with error handling...');
errorStream().listen(
(data) {
print(data);
},
onError: (error) {
print('Caught error: $error'); // Output: Caught error: Exception: Error at value 3
},
onDone: () {
print('Stream is done.');
},
);
}
Using Broadcast Streams
Broadcast streams allow multiple listeners to receive the same events. You can create a broadcast stream using the asBroadcastStream
method.
Example of Broadcast Streams
StreamController<int> controller = StreamController<int>.broadcast();
void main() {
controller.stream.listen((data) {
print('Listener 1: $data');
});
controller.stream.listen((data) {
print('Listener 2: $data');
});
for (int i = 1; i <= 3; i++) {
controller.add(i); // Sending data to all listeners
}
controller.close(); // Closing the stream
}
Conclusion
Streams are a powerful feature in Dart for handling asynchronous data sequences. By using streams, you can efficiently manage real-time data flows in your applications, whether from user interactions, network requests, or other sources. Understanding how to create, listen to, and manage streams will enhance your ability to build responsive and dynamic Dart applications.
PLAY QUIZ