Flutter StreamBuilder vs FutureBuilder
Solution 1:
Both StreamBuilder
and FutureBuilder
have the same behavior: They listen to changes on their respective object. And trigger a new build when they are notified
of a new value.
So in the end, their differences are how the object they listen to works.
Future
is like Promise
in JS or Task
in c#. They are the representation of an asynchronous request. Futures
have one and only one response. A common usage of Future
is to handle HTTP calls. What you can listen to on a Future
is its state. Whether it's done, finished with success, or had an error. But that's it.
Stream
on the other hand is like async Iterator
in JS. This can be assimilated to a value that can change over time. It usually is the representation of web-sockets or events (such as clicks). By listening to a Stream
you'll get each new value and also if the Stream
had an error or completed.
How each of them listens to changes in a dynamic list?
A Future
can't listen to a variable change. It's a one-time response. Instead, you'll need to use a Stream
.
Solution 2:
FutureBuilder
is used for one time response, like taking an image from Camera, getting data once from native platform (like fetching device battery), getting file reference, making an http request etc.
On the other hand, StreamBuilder
is used for fetching some data more than once, like listening for location update, playing a music, stopwatch, etc.
Here is full example mentioning both cases.
FutureBuilder
solves a square value and returns the result after 5 seconds, till then we show progress indicator to the user.
StreamBuilder
shows a stopwatch, incrementing _count
value by 1 every second.
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _count = 0; // used by StreamBuilder
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFutureBuilder(),
SizedBox(height: 24),
_buildStreamBuilder(),
],
),
);
}
// constructing FutureBuilder
Widget _buildFutureBuilder() {
return Center(
child: FutureBuilder<int>(
future: _calculateSquare(10),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done)
return Text("Square = ${snapshot.data}");
return CircularProgressIndicator();
},
),
);
}
// used by FutureBuilder
Future<int> _calculateSquare(int num) async {
await Future.delayed(Duration(seconds: 5));
return num * num;
}
// constructing StreamBuilder
Widget _buildStreamBuilder() {
return Center(
child: StreamBuilder<int>(
stream: _stopwatch(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active)
return Text("Stopwatch = ${snapshot.data}");
return CircularProgressIndicator();
},
),
);
}
// used by StreamBuilder
Stream<int> _stopwatch() async* {
while (true) {
await Future.delayed(Duration(seconds: 1));
yield _count++;
}
}
}
Solution 3:
I find that sometimes real-world analogies work well for explaining / remembering concepts. Here's one - it's not perfect but it helps me.
Think that you are at one of those modern sushi restaurants where you have a belt going around the room with sushi boats on it. You just sit down and wait till one goes by, grab it and eat. But they also allow you to order carry out.
A Future is like the token with a number on it that they give you when you order takeout; you made the request, but the result is not yet ready but you have a placeholder. And when the result is ready, you get a callback (the digital board above the takeout counter shows your number or they shout it out) - you can now go in and grab your food (the result) to take out.
A Stream is like that belt carrying little sushi bowls. By sitting down at that table, you've "subscribed" to the stream. You don't know when the next sushi boat will arrive - but when the chef (message source) places it in the stream (belt), then the subscribers will receive it. The important thing to note is that they arrive asynchronously (you have no idea when the next boat/message will come) but they will arrive in sequence (i.e., if the chef puts three types of sushi on the belt, in some order -- you will see them come by you in that same order)
From a coding perspective -- both Futures and Streams help you deal with asynchrony (where things don't happen instantly, and you don't know when you will get a result after you make a request).
The difference is that Futures are about one-shot request/response (I ask, there is a delay, I get a notification that my Future is ready to collect, and I'm done!) whereas Streams are a continuous series of responses to a single request (I ask, there is a delay, then I keep getting responses until the stream dries up or I decide to close it and walk away).
Hope that helps.
Solution 4:
FutureBuilder
It has one and only one response. A very common usage of flutter Future is during the http calls. What you can do with Future is to listen to it's state, that is, when it is done or had an error after the fetching data is done via Future
In the case of FutureBuilder we read this caution in the Flutter docs:
The future must have been obtained earlier, ..... If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.
In many tutorials I see something like this :
FutureBuilder(
future : foo.asyncMethod();
builder : (context, snapshot){
}
)
This is not good, because each time the build process is invoked the async method is called and the builder of the FutureBuilder is invoked.
If your use case is to just get the data, and display it, like Total number of courses from a class from API. Then you can use FutureBuilder
.
StreamBuilder
Stream on the other hand are Iterators, that it can assimilate different values, which will change over time. By using Stream, you will get each new values and also if it has some error or it is done with a success message
What if, the data updates every second or minute, while you use the app, like upcoming posts in a blog or increase comments on the blog or increase in likes on the blog. It updates asynchronously at certain interval, in that case StreamBuilder
is the best option.