Flutter Async Load Multiple Functions One After The Other

286

Solution 1

It seems like the load() function itself completes before the loadFeed() Future is finished, how can I fix that?

That's exactly what's wrong. You do:


load(int categoryIndex, String _url) async {
  loadFeed(_url).then((result) {
    // ... bunch of code...
  });
}

Your load function calls loadFeed, registers a Future.then callback, ignores the newly returned Future, and synchronously returns to the caller after callback registration. It does not use await to wait for the Future to complete, nor does it return the Future to the caller to allow the caller to wait for the Future.

It's much simpler if you use async/await instead of mixing it with the raw Future API:

Future<void> load(int categoryIndex, String _url) async {
  var result = await loadFeed(_url);
  // ... bunch of code...
}

Additionally, enabling the unawaited_futures lint in your analysis_options.yaml file would have caught this problem during static analysis.

Solution 2

In future functions, you can use whencomplete, from the documentation:

"WhenComplete", Registers a function to be called when this future completes.

The [action] function is called when this future completes, whether it does so with a value or with an error.

This is the asynchronous equivalent of a "finally" block.

  • Change load into a future function, and add a return value to let dart know that you are done, like this:

    Future load(int categoryIndex, String _url) async {
       loadFeed(_url).then((result) {
         if (null == result || result.toString().isEmpty) {
           print("error");
           return;
         }
         data.value = [[],[],[],];
         for (var i = 0; i < result.items.length; i++) {
           data.value[categoryIndex].add(result.items[i]);
         }
        return data.notifyListeners(); //add a return here, to tell dart that this function is done.
       });
     }
    
  • Change your loadAll into this:

    loadAll() async { 
    await load(0, 'url1')
    .whenComplete(() async => await load(1, 'url2')
    .whenComplete(() async => await load(2, 'url3')));}
    
Share:
286
Leo D.
Author by

Leo D.

Updated on December 28, 2022

Comments

  • Leo D.
    Leo D. over 1 year

    How can I let Flutter know to wait for one function (and therefore the future) to complete, until the next function is called? It seems like the load() function itself completes before the loadFeed() Future is finished, how can I fix that?

    Here is my current code:

    ValueNotifier<List> data = ValueNotifier([]);
    ValueNotifier<bool> loading = ValueNotifier(true);
    
    loadAll() async {
      await load(0, 'url1');
      print("0 finished");
      await load(1, 'url2');
      print("1 finished");
      await load(2, 'url3');
      print("2 finished");
    }
    
    load(int categoryIndex, String _url) async {
      loadFeed(_url).then((result) {
        if (null == result || result.toString().isEmpty) {
          print("error");
          return;
        }
        data.value = [[],[],[],];
        for (var i = 0; i < result.items.length; i++) {
          data.value[categoryIndex].add(result.items[i]);
        }
        data.notifyListeners();
      });
    }
    
    Future<RssFeed> loadFeed(String _url) async {
      loading.value = true;
      try {
        final client = http.Client();
        final response = await client.get(Uri.parse(_url));
    
        return RssFeed.parse(response.body);
      } catch (e) {
        print("error");
      } finally {
        loading.value = false;
      }
      return null;
    }
    
  • jamesdlin
    jamesdlin about 3 years
    You don't need to use .whenComplete() if you're already using await.