'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