What Is Flutter Stream Use For
Streams in Flutter (and Dart) are a way to handle asynchronous data. They provide a continuous flow of data over time, which can be listened to and processed as it arrives. This is particularly useful for handling data from sources like network requests, user input events, and data updates in real-time applications.
Key Concepts of Streams
Single-Subscription Streams:
Can have only one listener at a time.
Used when you want to handle a single sequence of events, like reading a file.
void main() {
Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);
stream.listen((data) {
print(data); // Output: 1, 2, 3, 4, 5
});
}
Broadcast Streams:
Can have multiple listeners simultaneously.
Used for events that can be listened to by multiple parts of the app, like user interactions or real-time updates.
void main() {
Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]).asBroadcastStream();
stream.listen((data) {
print('Listener 1: $data'); // Output: Listener 1: 1, Listener 1: 2, ...
});
stream.listen((data) {
print('Listener 2: $data'); // Output: Listener 2: 1, Listener 2: 2, ...
});
}
StreamController:
Used to create a new stream and manage its listeners.
Can add data, error, and done events to the stream.
import 'dart:async';
void main() {
final controller = StreamController<int>();
controller.stream.listen((data) {
print(data); // Output: 1, 2, 3, 4, 5
});
controller.add(1);
controller.add(2);
controller.add(3);
controller.add(4);
controller.add(5);
controller.close();
}
Asynchronous Generators:
- Functions that return a stream and use
yield
to provide data.
- Functions that return a stream and use
Stream<int> asyncGenerator() async* {
for (int i = 1; i <= 5; i++) {
yield i;
}
}
void main() {
asyncGenerator().listen((data) {
print(data); // Output: 1, 2, 3, 4, 5
});
}
Streams in Flutter
In Flutter, streams are commonly used for:
Handling user input (e.g., text field changes).
Fetching and updating data from a backend.
Managing state in reactive programming.
Example: StreamBuilder
StreamBuilder
is a widget in Flutter that builds its content based on the latest snapshot of interaction with a stream. It automatically updates the UI when new data arrives.
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('StreamBuilder Example')),
body: CounterScreen(),
),
);
}
}
class CounterScreen extends StatefulWidget {
@override
_CounterScreenState createState() => _CounterScreenState();
}
class _CounterScreenState extends State<CounterScreen> {
final StreamController<int> _controller = StreamController<int>();
int _counter = 0;
void _incrementCounter() {
_counter++;
_controller.add(_counter);
}
@override
void dispose() {
_controller.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
StreamBuilder<int>(
stream: _controller.stream,
initialData: _counter,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return Text('Counter: ${snapshot.data}');
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increment'),
),
],
),
);
}
}
Summary
Streams in Dart and Flutter provide a powerful way to handle asynchronous data. They allow you to work with data that arrives over time, making it easier to build reactive and real-time applications. By using Stream
, StreamController
, and StreamBuilder
, you can efficiently manage and update your app's state based on real-time data.