'How to make 2 FutureBuilders wait on the same Future in Flutter?
I have a Future
which, when complete, adds some data to a ChangeNotifierProvider
. Then I use the data in the ChangeNotifierProvider to populate some ListViews
. The thing is, I have 2 screens that both get the data they need from that same Future. Each screen has a FutureBuilder that return a ListView.
How do I make the 2 FutureBuilders wait on the "same" future, without calling it 2 times?
Is FutureProvider a solution?
Solution 1:[1]
you can find a solution when using a variable.
let's say that fetchData() is your function in your provider class.
Future<void> initializeData = provider.fetchData(); //fetchData called here
now use
initializeData
variable as a future in all the FutureBuilders
FutureBuilder(
future: initializeData,
builder: (ctx, snapShot) {} );
Solution 2:[2]
You should use Future.wait
API, what it does is to wait until all futures are complete and it returns its results or errors.
See this as example:
Future<String> getData() async {
final future1 = Future<String>.delayed(Duration(seconds: 1), () => "I am");
final future2 = Future<int>.delayed(Duration(seconds: 2), () => 100);
final future3 = Future<String>.delayed(Duration(seconds: 3), () => "Years old!");
final results = await Future.wait([future1, future2, future3]);
// Doing a simple cast considering my Future will never fails in this example, you should check for exceptions/errors!
final future1ResultOrError = results.first as String;
final future2ResultOrError = results[1] as int;
final future3ResultOrError = results[2] as String;
return "$future1ResultOrError $future2ResultOrError $future3ResultOrError";
}
You use it like a single Future:
FutureBuilder(
future: getData(),
initialData: null,
builder: (context, shot) {
return Text(shot.hasData ? shot.data : "Waiting for data...");
},
),
This will print: "I am 100 Years old!". Notice how it loads the data from different Futures!
Edit:
You may want to have a single Future and provide it to the two FutureBuilder. See the code bellow:
class _MyState extends State<MyPage> {
Future mySingleFuture;
Future<String> getData() async {
final future1 = Future<String>.delayed(Duration(seconds: 1), () => "I am");
final future2 = Future<int>.delayed(Duration(seconds: 2), () => 100);
final future3 = Future<String>.delayed(Duration(seconds: 3), () => "Years old!");
final results = await Future.wait([future1, future2, future3]);
// Doing a simple cast considering my Future will never fails in this example, you should check for exceptions/errors!
final future1ResultOrError = results.first as String;
final future2ResultOrError = results[1] as int;
final future3ResultOrError = results[2] as String;
return "$future1ResultOrError $future2ResultOrError $future3ResultOrError";
}
@override
void initState() {
super.initState();
mySingleFuture = getData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FutureBuilder(
future: getData(),
initialData: null,
builder: (context, shot) {
return Text(shot.hasData ? shot.data : "Waiting for data...");
},
),
FutureBuilder(
future: getData(),
initialData: null,
builder: (context, shot) {
return Text(shot.hasData ? shot.data : "Waiting for data 2...");
},
),
],
),
),
);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | ItayL |
Solution 2 |