Understanding Streams: Everything you need to know
What is Stream? Types of Streams? How to use and manipulate the Streams? How to create your own Stream? What is StreamBuilder and how to use it?

Search for a command to run...
What is Stream? Types of Streams? How to use and manipulate the Streams? How to create your own Stream? What is StreamBuilder and how to use it?

It is one of the very good article I have been opportune to stumble across.... I am giving the writer an accolades.
Hey Dhruv, It's Nick again. I am a fan now, if the blocc article hits as hard as this then I will be reading even the react articles.
Lessons from Code, Content, and Consistency

Reliability basics: Outbox pattern + why it matters

Introducing Kafka/Redpanda + move to event-driven workflow

Connect Orders ↔ Inventory (first working service-to-service flow)

Inventory service + gRPC + proto contracts


async and await.async and await are keywords that are used to define an asynchronous function.someAsyncFunction () async{
await getData();
}


listener to listen to the stream. If you try to listen to the same stream again, you'll get an exception. The Broadcast Stream allows more than one listener to listen to the same stream.listener listens to the particular event of the stream. Whenever data flows in the Streams the listener will recognize that event and listens to it.async* is used when a function returns multiple future values one at a time.yield or yield*.yield doesn't terminate the function immediately.Stream<int> numberGenerator() async*{
for(int i=0; i<10; i++){
await Future.delayed(Duration(milliseconds: 1000));
yield i;
}
}
void main() {
final myStream = numberGenerator();
final subscription= myStream.listen(
(data)=>{
print("Number: $data")
}
);
}

subscription is a type of StreamSubscription. When you listen on a Stream using Stream.listen, a StreamSubscription object is returned.subscription provides events to the listener, and holds the callbacks used to handle the events. The subscription can also be used to unsubscribe from the events, or to temporarily pause the events from the stream.subscription starts listening to the myStream, one by one all the integer values start flowing into the stream.yield that int values one by one asynchronously.listen() properties:null, nothing happens. void main() {
final myStream = numberGenerator();
final subscription = myStream.listen(
(data)=>{ // data handler function
print("Number: $data")
}
);
}
void main() {
final myStream = timedCounter();
final subscription = myStream.listen(
(data){
print("Number: $data");
},
onDone: () {
print("You've reached at the end");
},
);
}
Stream<int> timedCounter() async* {
int i = 0;
while (i <= 5) {
await Future.delayed(Duration(milliseconds: 1000));
yield i++;
}
}
onDone function is executed.
void main() {
final myStream = timedCounter();
final subscription = myStream .listen(
(data){
print("Number: $data");
},
onDone: () {
print("You've reached at the end");
},
onError: (e){
print("Error: $e");
},
);
}
Stream<int> timedCounter() async* {
int i = 0;
while (i <= 5) {
await Future.delayed(Duration(milliseconds: 1000));
if(i ==2){
throw Exception("Error Occurred");
}
yield i++;
}
}
2 is encountered we've thrown an error and onError function executed.

cancelOnError is true, the subscription is automatically canceled when the first error event is delivered. The default is false.error is encountered, the stream has not stopped its execution. It executed onDone too. To close the stream subscription as soon as the error is encountered we have to give true value to
cancelOnError.void main() {
final myStream = timedCounter();
final subscription = myStream.listen(
(data){
print("Number: $data");
},
onDone: () {
print("You've reached at the end");
},
onError: (e){
print("Error: $e");
},
cancelOnError: true
);
}
Stream<int> timedCounter() async* {
int i = 0;
while (i <= 5) {
await Future.delayed(Duration(milliseconds: 1000));
if(i ==2){
throw Exception("Error Occurred");
}
yield i++;
}
}

map, where, take and expand.iterable(like, elementAt, cast, contains, any, etc) to manipulate the data of the streamvoid main() {
final myStream = timedCounter()
.map((data)=> 'Number : ${data*2}')
.listen(print);
}
Stream<int> timedCounter() async* {
int i = 0;
while (i <= 5) {
await Future.delayed(Duration(milliseconds: 1000));
yield i++;
}
}

void main() {
final myStream = timedCounter()
.where((data) => data % 2 == 0)
.map((data)=> 'Number : $data')
.listen(print);
}
Stream<int> timedCounter() async* {
int i = 0;
while (i <= 5) {
await Future.delayed(Duration(milliseconds: 1000));
yield i++;
}
}

listen() method as we've seen in the above examples.void main() {
final myStream = timedCounter();
final subscription = myStream.listen(
(data){
print("Number: $data");
},
);
}
Stream<int> timedCounter() async* {
int i = 0;
while (i <= 5) {
await Future.delayed(Duration(milliseconds: 1000));
yield i++;
}
}

void main() {
final myStream = timedCounter();
final subscriber1 = myStream.listen(
(data){
print("Sub 1 : Number: $data");
},
);
final subscriber2= myStream.listen(
(data){
print("Sub 2 : Number: $data");
},
);
}
Stream<int> timedCounter() async* {
int i = 0;
while (i <= 5) {
await Future.delayed(Duration(milliseconds: 1000));
yield i++;
}
}

asBroadcastStream() is used to make any stream a Broadcast Stream.void main() {
final myStream = timedCounter().asBroadcastStream();
final subscriber = myStream.listen(
(data){
print("Sub 1 : Number: $data");
},
);
final subscriber2 = myStream.map(
(data)=> 'Sub 2 : Number : ${data*2}'
).listen(print);
}
Stream<int> timedCounter() async* {
int i = 0;
while (i <= 5) {
await Future.delayed(Duration(milliseconds: 1000));
yield i++;
}
}

dart:io package inside your application.import 'dart:async';
void main() {
final _streamController = StreamController<int>(); // initialization of StreamController
int _number = 1;
addData() {
Timer.periodic(Duration(seconds: 1),(_) {
_streamController.sink.add(_number); // adding data to stream
_number++;
});
}
addData();
Stream<int> myStream = _streamController.stream; //creating a stream
final subscription = myStream.listen( // listening to the stream
(data) => {
print(data)
},
);
}

import 'dart:async';
void main() {
final _streamController = StreamController<int>();
int _number = 1;
addData() {
Timer.periodic(Duration(seconds: 1),(_) {
if(_number == 5){
_streamController.close(); // closing a stream
return;
}
_streamController.sink.add(_number);
_number++;
});
}
addData();
Stream<int> myStream = _streamController.stream;
final subscription = myStream.listen(
(data) => {
print(data)
},
onDone: (){
print("All data received"); // called when stream is closed
}
);
}

onListen, onPause, onCancel, onResume using StreamController.StreamController<int>(
onListen: ...,
onPause: ...,
onResume: ...,
onCancel: ...
);
stream property.StreamBuilder(
stream: myStream
//...
)
builder property is used to return a Widget that we want to display on the screen.context and a snapshot as a parameterStreamBuilder(
stream: myStream,
builder: (context, snapshot) {
return Container()
}
)
initialValue property of the StreamBuilder is used to give the initial data to the widget while it's waiting for the first event.snapshot has data or not, has any error or not and also the connection state :StreamBuilder(
stream: myStream,
builder: (context, snapshot) {
if(!snapshot.hasData) return CircularProgressIndicator() //checking is there any data
if(snapshot.hasError) return Text("Something went wrong") //cheking for the error
if(snapshot.connectionState == ConnectionState.done){} // or `waiting`,`none`, `active`
return Container()
}
)
class FlutterStreamBuilder extends StatefulWidget {
@override
_FlutterStreamBuilderState createState() => _FlutterStreamBuilderState();
}
class _FlutterStreamBuilderState extends State<FlutterStreamBuilder> {
final colorStream = StreamController<Color>();
// generate new Color randomly
Color generateColor() {
final random = Random();
return Color.fromARGB(
255,
random.nextInt(255),
random.nextInt(255),
random.nextInt(255),
);
}
// add Color to `colorStream`
addData(){
colorStream.sink.add(generateColor());
}
@override
void initState() {
addData();
super.initState();
}
@override
void dispose() {
colorStream.close(); // To prevent memory leak, Make Sure you close the Stream.
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
StreamBuilder(
stream: colorStream.stream,
builder:
(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (!snapshot.hasData) {
return Center(child:CircularProgressIndicator());
}
if (snapshot.connectionState == ConnectionState.done) {}
return Container(
height: 220,
width: 220,
color: snapshot.data,
);
}),
SizedBox(height:30),
ElevatedButton(onPressed: addData, child: Text("Click"))
],
),
),
);
}
}

