Search code examples
flutterdartfuture

Future.wait did not execute it's items after the first time


There are two pages: page1 and page2.

page1 pass List<Future> to page2, page2 execute these futures.

Below is all the source code:

class _Page1 extends StatelessWidget {
  const _Page1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('page 1'),
      ),
      body: ElevatedButton(
        child: Text('push page 2'),
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => _Page2(
                requests: [_load1(), _load2()],
              ),
            ),
          );
        },
      ),
    );
  }

  Future<void> _load1() {
    return Future.delayed(Duration(seconds: 1), () {
      log('load1 finish');
    });
  }

  Future<void> _load2() {
    return Future.delayed(Duration(seconds: 2), () {
      log('load2 finish');
    });
  }
}

class _Page2 extends StatelessWidget {
  const _Page2({Key? key, required this.requests}) : super(key: key);

  final List<Future> requests;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('page 2'),
      ),
      body: ElevatedButton(
        child: Text('future wait'),
        onPressed: () {
          Future.wait(requests).then((value) {
            log('all finish');
          });
        },
      ),
    );
  }
}

The first time click page2 button, log: load1 finish, load2 finish, all finish.

But after the first time, it's only log all finish.

Why? And how to change it to log load1 finish, load2 finish, all finish everytime click page2 button?


Solution

  • Your list requests in _Page2 is a list of future and not a function, meaning it is only returning the one-time result. So when you say Future.wait(requests), you are telling it to just listen for the return result which was already done, but not asking it to execute the function.

    If you want to execute the function after clicking the 'future wait' button, you have to turn the list into a Function.

    final List<Function> requests;
    

    So now you pass the object from page1 like this:

      onPressed: () {
          _load1();
          _load2();
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => _Page2(
                requests: [_load1, _load2],
              ),
            ),
          );
        },
    

    So now you call the future wait to do its function after executing the functions in your request list like this:

              Future.wait(requests.map((e) => e())).then((value) {
                log('all finish');
                debugPrint('all finish');
              });