A stream is one of the challenging topics for the beginner. It took lots of efforts to understand. In order to understand the Streams, you will need to go through the various Examples and then you will get what Exactly Streams is.
At the end of the post, I will write one Flutter application which will be based on the same example which I had discussed in Dart.
I am also going to put my understanding of Streams into the words and Examples.
Streams are a concept Dart. So, I will start streams in Dart and end with applying those concepts in Flutter.
Asynchronous programming in Dart is characterized by the Future and Stream classes.
A simple Example of Future with potential value.
// asynchronous data
main() async {
String x = await HelloAsync();
print(x);
}
Future<String> HelloAsync() async{
await Future.delayed(Duration(seconds:5));
return 'Message from Future.';
}
How stream and Future are similar?
How stream and Future are different?
If you had ever sent any request to any API in your flutter application then probably you know about async ( Future ).
There are two kinds of streams :
All the example which I will discuss in this post will be Single Subscription based. Once you understand the single subscription then you can easily understand the Broadcast.
Let’s understand this with examples
The main purpose of this example is to let you understand how the streams work. These examples will make you familiar with some available methods and property of the Stream.
All the available example can be run on Dartpad. I highly recommend you to run the examples and see the pattern of output and understand them.
Stream .periodic() → Stream
// asynchronous data
main() async {
Duration interval = Duration(seconds: 2);
Stream<int> stream = Stream<int>.periodic(interval, callback);
await for(int i in stream){
print(i);
}
}
// This callback modify the given value to even number.
int callback(int value){
return ( value + 1 ) * 2;
}
Let’s understand the creation of the stream.
Stream .periodic: Creates a stream that repeatedly emits events at period
intervals.
This is one of the basic streams which you can create easily to make anyone understand about the stream.
If callback
is omitted the event values will all be null
.
2 second.
Stream.take(int count) → Stream
Let’s create a finite stream
// asynchronous data
main() async {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval,transform);
// Added this statement
stream = stream.take(5);
await for(int i in stream){
print(i);
}
}
int transform(int x){
return (x + 1) * 2;
}
Stream.takeWhile(bool test(T element)) → Stream
You can specify the condition on the returned value also.
// asynchronous data
main() async {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval,transform);
// Added this statement
stream = stream.takeWhile(condition);
await for(int i in stream){
print(i);
}
}
int transform(int x){
return (x + 1) * 2;
}
// Added this function
bool condition(int x){
return x <= 10;
}
Stream.skip(int count) → Stream
You can skip some first emitted event.
// asynchronous data
main() async {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval,transform);
stream = stream.take(10);
stream = stream.skip(2);
await for(int i in stream){
print(i);
}
}
int transform(int x){
return (x + 1) * 2;
}
Stream.skipWhile(bool test(T element)) → Stream
You can skip the event based on the event value too.
// asynchronous data
main() async {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval,transform);
stream = stream.take(10);
stream = stream.skipWhile(condition);
await for(int i in stream){
print(i);
}
}
int transform(int x){
return (x + 1) * 2;
}
bool condition(int x){
return x < 5;
}
Stream.toList() → Future<List>
This method collects all the data from the stream and store in the List.
// asynchronous data
main() async {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval,transform);
stream = stream.take(5);
List<int> data = await stream.toList();
for(int i in data){
print(i);
}
}
int transform(int x){
return (x + 1) * 2;
}
Stream. listen() → StreamSubscription
There is one specific method for listening to the stream on data. I like the for loop approach because it is much more friendly.
// asynchronous data
main() async {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval,transform);
stream = stream.take(10);
stream.listen((x){
print(x);
});
}
int transform(int x){
return (x + 1) * 2;
}
Stream. forEach() → Future
There is one specific method for listening to the stream on data. I like the for loop approach because it is much more friendly.
// asynchronous data
main() async {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval,transform);
stream = stream.take(10);
stream.forEach((int x){
print(x);
});
}
int transform(int x){
return (x + 1) * 2;
}
Stream .length → Future
// asynchronous data
main() async {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval);
stream = stream.take(10);
print(await stream.length);
}
Now I will create a simple flutter application which will be based on the above example. I am pretty sure you will understand how the stream works in a flutter application. There are various ways of using the stream in flutter application. I am showing you one of them.
To build app something like this, every beginner will use build a Stateful Widget and will probably use the setState((){}) again and again to update the UI.
I am going to build the exact same app which is shown in the image
What is this StreamBuilder?
StreamBuilder listen to the stream and build itself on every new emitted Event by the stream.
Let’s see then stream Builder Implementation.
child: StreamBuilder<T>(
stream: stream, // a Stream<int> or null
builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
if (snapshot.hasError) return Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Not connected to the Stream or null');
case ConnectionState.waiting:
return Text('awaiting interaction');
case ConnectionState.active:
return Text('Stream has started but not finished');
case ConnectionState.done:
return Text('Stream has finished');
}
},
),
You can see the above Example and get some idea about the StreamBuilder. Stream Builder needs two things.
Connection State
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: HomePage(),
title: 'Stream Demo',
));
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Stream Demo'),
),
body: Center(
child: StreamBuilder(
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(
'1 Minute Completed',
style: TextStyle(
fontSize: 30.0,
),
);
} else if (snapshot.connectionState == ConnectionState.waiting) {
return Text(
'Waiting For Stream',
style: TextStyle(
fontSize: 30.0,
),
);
}
return Text(
'00:${snapshot.data.toString().padLeft(2,'0')}',
style: TextStyle(
fontSize: 30.0,
),
);
},
initialData: 0,
stream: _stream(),
),
),
);
}
Stream<int> _stream() {
Duration interval = Duration(seconds: 1);
Stream<int> stream = Stream<int>.periodic(interval, transform);
stream = stream.take(59);
return stream;
}
int transform(int value) {
return value;
}
}
This code is using two main thing
#flutter #mobileaps #webdev