Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does notifyListeners() sometimes complete asynchronously?

Tags:

flutter

I am calling notifyListeners() towards the end of a class which returns a Future, just before the return statement. The actions initiated by notifyListeners do not fully complete before the return is called and subsequent statements are processed, resulting in errors. It appears that notifyListeners is somehow completing asynchronously.

I asked about this on an alternate forum and was told that this is a common flutter bug, particularly in relation to animation. It seems to me more likely that I am doing something wrong with my syntax. Has anyone come across this 'bug' before?

I tried using both .then() and async / await. Both have the same outcome.

Future<bool> updateProduct(Map<String, dynamic> updatedProduct)

...

return http
    .put(
        'https://chocolate-f3e81.firebaseio.com/products/${newProduct.serverID}.json',
        body: json.encode(newProductMap))
    .then<bool>((http.Response response) {
  if (response.statusCode == 200 || response.statusCode == 201) {
    _products[selectedProductIndex] = newProduct;
    setIsLoading(false);
    print('model selectedProductIndex ${selectedProductIndex}');
    print('model selectedProductServerID ${_selectedProductServerID}');
     notifyListeners();
    return true;

I expected everything initiated by notifyListeners() to complete before 'return true' is actioned. This does not happen, instead the return is actioned and other code continues and gets ahead of the code initiated by notifyListeners().

like image 576
Dan Horton Avatar asked Dec 27 '18 13:12

Dan Horton


2 Answers

In fact, the notifyListeners() will actually behave asynchronously since it schedules a microtask by using scheduleMicrotask() to call all the registered listeners.

According to the official documentation

Callbacks registered through this function are always executed in order and are guaranteed to run before other asynchronous events (like Timer events, or DOM events).

Only comes in mind an ugly solution that might work for your case, which is to run an await Future.delayed(Duration(milliseconds: 300)) just before return true in order to give it a little time to complete its task.

like image 97
Miguel Ruivo Avatar answered Oct 08 '22 13:10

Miguel Ruivo


No. The only way for .then to be called synchronously is to use SynchronousFuture, which is a custom reimplementation of the future.

If not, then the call is asynchronous even if the future completes immediately.

like image 26
Rémi Rousselet Avatar answered Oct 08 '22 13:10

Rémi Rousselet