If you've been developing Flutter applications, you're likely familiar with the concept of state management. Managing the application state is crucial to building robust, responsive, and maintainable apps. While there are various state management techniques available, today we'll dive into one of the most popular and powerful options: Flutter Stream Provider.
Flutter Stream Provider is a state management solution that leverages the power of the Dart Stream API and the simplicity of Flutter's Provider package. It allows you to easily handle and propagate changes to your application state throughout your widget tree.
In Flutter, a stream is a sequence of asynchronous events. These events can be of two kinds: data events or error events. A data event represents a chunk of data, while an error event signifies that an error occurred while processing the stream.
A data event is a type of event that carries a piece of data. For example, when new data arrives from a server, a data event is added to the stream. The stream provider listens to these data events and rebuilds the widgets that depend on it.
An error event, on the other hand, signifies that an error occurred while processing the stream. The stream provider can listen to these error events and respond accordingly, such as by showing an error message to the user.
The stream class in Flutter is a fundamental part of working with streams. It provides a way to receive events—data, error, or a signal that no more events will be added. The stream class has a listen function that you can use to start listening to events.
The stream provider is a part of the provider package in Flutter. It is used to expose a stream and allows its descendants to access the latest value of the stream. The stream provider listens to a stream and exposes the latest value it has emitted.
In Dart and Flutter, there are two main types of streams: single subscription streams and broadcast streams. These two types of streams differ primarily in the number of subscribers they can have.
A single subscription stream is a type of stream that allows only a single listener during the whole lifetime of the stream. It means once a listener starts listening to the stream, no other listener can be added. This type of stream is useful when there is a single consumer for the data.
For example, if you are reading a file, you would typically use a single subscription stream. The data is read sequentially, and once read, it cannot be read again. Here's an example of creating a single subscription stream:
1Stream<int> countStream() async* { 2 for (var i = 1; i <= 10; i++) { 3 await Future.delayed(Duration(seconds: 1)); 4 yield i; 5 } 6}
In this example, countStream is a single subscription stream. It emits a new event every second for 10 seconds. The yield keyword is used to emit a new event to the stream.
On the other hand, broadcast streams are streams that allow multiple listeners. This means that more than one listener can listen to the events of the stream simultaneously. When a new event is added to the stream, all the listeners receive the event.
Broadcast streams are useful when you have multiple independent consumers who all need to receive the same events. An example of a broadcast stream is a button click event. Multiple listeners might want to react to the button click event in different ways.
Here's an example of creating a broadcast stream:
1StreamController<int> streamController = StreamController<int>.broadcast(); 2 3streamController.stream.listen((data) { 4 print("DataReceived: "+data.toString()); 5}); 6 7streamController.stream.listen((data) { 8 print("DataReceived Again: "+data.toString()); 9}); 10 11for(int i=1; i<=5; i++){ 12 streamController.sink.add(i); 13}
In this example, we create a broadcast stream using StreamController.broadcast(). We then add two listeners to the stream. When we add data to the stream using streamController.sink.add(i), both listeners receive the data.
The stream provider is an essential part of the Flutter Provider package. It allows you to manage and manipulate streams of data effectively. The two main aspects of working with a stream provider are creating a stream provider and listening to a stream.
Creating a stream provider is a straightforward process. The first step is to define a stream. A stream is a sequence of asynchronous data events. It's created by calling a t function on an object.
Let's consider an example where we create a new stream that emits a new event every second. This is done using the Stream.periodic function, which creates a new stream that generates a sequence of values every period.
1Stream<int> countStream() async* { 2 for (var i = 1; i <= 10; i++) { 3 await Future.delayed(Duration(seconds: 1)); 4 yield i; 5 } 6}
In the above example, countStream is a stream that emits a new event every second for 10 seconds. The yield keyword is used to emit a new event to the stream.
Once the stream is defined, you can create a stream provider. The stream provider is created using the StreamProvider class. You need to pass the stream to the StreamProvider class.
1class MyApp extends StatelessWidget { 2 3 Widget build(BuildContext context) { 4 return StreamProvider<int>.value( 5 value: countStream(), 6 initialData: 0, 7 child: MaterialApp( 8 home: Home(), 9 ), 10 ); 11 } 12}
In the above example, MyApp is a stream provider that provides the stream countStream to its descendants. The initialData parameter is used to specify the initial data of the stream.
Once you have a stream provider, you can start listening to it. When new data arrives, the stream provider will automatically re-build the widgets that depend on it. This is done using the Provider.of<T>
method.
1class Home extends StatelessWidget { 2 3 Widget build(BuildContext context) { 4 var count = Provider.of<int>(context); 5 return Scaffold( 6 appBar: AppBar( 7 title: Text('Count: $count'), 8 ), 9 body: Center( 10 child: Text('Button pressed $count times'), 11 ), 12 ); 13 } 14}
In the above example, Home is a widget that listens to the stream provider MyApp. Whenever a new event is emitted by the stream, the Home widget is re-built with the new data.
Listening to a stream is an essential part of working with stream providers. It allows you to create dynamic and responsive apps that can react to data events in real-time.
Let's look at an example. We'll create a simple Flutter app using the stream provider.
1void main() { 2 runApp(const MyApp()); 3} 4 5class MyApp extends StatelessWidget { 6 7 Widget build(BuildContext context) { 8 return StreamProvider<int>.value( 9 value: countStream(), 10 initialData: 0, 11 child: MaterialApp( 12 home: Home(), 13 ), 14 ); 15 } 16} 17 18Stream<int> countStream() async* { 19 for (var i = 1; i <= 10; i++) { 20 await Future.delayed(Duration(seconds: 1)); 21 yield i; 22 } 23} 24 25class Home extends StatelessWidget { 26 27 Widget build(BuildContext context) { 28 var count = Provider.of<int>(context); 29 return Scaffold( 30 appBar: AppBar( 31 title: Text('Count: $count'), 32 ), 33 body: Center( 34 child: Text('Button pressed $count times'), 35 ), 36 ); 37 } 38}
In this example, we have a simple counter app. The countStream function generates a new event every second. The StreamProvider listens to these events and rebuilds the Home widget every time a new event is received.
In conclusion, the stream provider is a powerful tool in Flutter that allows you to work with streams in a reactive way. It listens to a stream and rebuilds the widgets that depend on it every time a new event is received. This makes it easy to create dynamic and responsive apps.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.