Step-by-Step Guide to Using StreamBuilder in Flutter

 


The StreamBuilder is a widget that builds itself based on the latest snapshot of interaction with a stream.

This is mainly used in applications like chat application clock applications where the widget needs to rebuild itself to show the current snapshot of data.

But today we will use this to make an app for increment and decrement of the counter value. (Yeah, It boring to see the same example, but this is a perfect example to show the usage of Streams).

Let’s first understand the StreamController, streams, and sink using a simple diagram.




Types of Streams

  • Single-subscription streams: Can only be listened to once. They are ideal for handling events that are intended to be consumed only once, like file I/O operations.
  • Broadcast streams: Allow multiple listeners and are useful for distributing the same data events to multiple listeners simultaneously.
 

Common Use Cases

  • File Operations: Reading or writing data to and from files in a non-blocking way.
  • Network Communications: Handling data from network connections like websockets or HTTP responses.
  • User Input: Capturing and responding to user interactions in UI applications.
Single-subscription streams:
import 'dart:async';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Stream Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: StreamExample(),
);
}
}

class StreamExample extends StatefulWidget {
@override
_StreamExampleState createState() => _StreamExampleState();
}

class _StreamExampleState extends State<StreamExample> {
// StreamController to manage our stream of integers
StreamController<int> _controller = StreamController<int>();

int _counter = 0;

Timer? _timer;


@override
void initState() {
super.initState();
// Start a timer to increment the counter every second
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
_incrementCounter();
});
}

@override
void dispose() {
// Dispose of the StreamController when the widget is disposed
_controller.close();
super.dispose();
}

void _incrementCounter() {
// Increment the counter and add the new value to the stream
_counter++;
_controller.add(_counter);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Stream Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Counter Value:',
),
SizedBox(height: 10),
// StreamBuilder to listen to the stream and update UI accordingly
StreamBuilder<int>(
stream: _controller.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
'${snapshot.data}',
style: TextStyle(fontSize: 36),
);
} else {
return CircularProgressIndicator();
}
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}







Broadcast streams:

class _StreamExampleState extends State<StreamExample> {
// Using a BroadcastStreamController to support multiple listeners
StreamController<int> _controller = StreamController<int>.broadcast();

int _counter = 0;
Timer? _timer;

@override
void initState() {
super.initState();
// Start a timer to increment the counter every second
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
_incrementCounter();
});
}

@override
void dispose() {
// Cancel the timer and close the stream controller to avoid leaks
_timer?.cancel();
_controller.close();
super.dispose();
}

void _incrementCounter() {
// Increment the counter and add the new value to the stream
_counter++;
_controller.add(_counter);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Multi-Listener Stream Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Counter Value from First Listener:',
),
SizedBox(height: 10),
// First StreamBuilder
StreamBuilder<int>(
stream: _controller.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
'${snapshot.data}',
style: TextStyle(fontSize: 36, color: Colors.red),
);
} else {
return CircularProgressIndicator();
}
},
),
SizedBox(height: 20),
Text(
'Counter Value from Second Listener:',
),
SizedBox(height: 10),
// Second StreamBuilder
StreamBuilder<int>(
stream: _controller.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
'${snapshot.data}',
style: TextStyle(fontSize: 36, color: Colors.green),
);
} else {
return CircularProgressIndicator();
}
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}






Comments

Popular posts from this blog

Unlocking the Power of OOP: A Beginner's Guide to Objects, Encapsulation, Inheritance, Abstraction, and Polymorphism

HTTP GET Response in Flutter

Building a Flutter Firebase Firestore CRUD App