简体   繁体   中英

Flutter: future not returned after closing alert dialog

I created a http method in Flutter like below:

  Future<void> addProduct(Product product) {
    const url = 'https://flutter-shop-3de16.firebaseio.com/products';
    return http
        .post(
      url,
      body: json.encode({
        'title': product.title,
        'description': product.description,
        'imageUrl': product.imageUrl,
        'price': product.price,
        'isFavorite': product.isFavorite,
      }),
    )
        .then((response) {
      ...
      notifyListeners();
    }).catchError((error) {
      print(error);
      throw error;
    });
  }

I know that my url is wrong because i want to get error.

In .catchError i throw an error and in the main page by provider i used addProduct like this:

      Provider.of<Products>(context, listen: false)
          .addProduct(_editedProduct)
          .catchError((error) {
        return showDialog(
          context: context,
          builder: (ctx) => AlertDialog(
            title: Text('An error occurred!'),
            content: Text('Something went wrong.'),
            actions: <Widget>[
              FlatButton(
                child: Text('Okay'),
                onPressed: () {
                  Navigator.of(ctx).pop();
                },
              )
            ],
          ),
        );
      }).then((_) {
        print('after catch accoured');
        setState(() {
          _isLoading = false;
        });
        Navigator.of(context).pop();
      });
    }
  }

I catchError i got error and i show an alert dialog.After tap on Okay button i want to execute then block so i returned showDialog because it return a future.

But i do not know why

.then((_) {
            print('after catch accoured');
            setState(() {
              _isLoading = false;
            });
            Navigator.of(context).pop();
          });
        }

No to run after alert dialog is closed?

注意

  • make sure using return showDialog<Null>() instead of return showDialog()
  • also have a try-catch with throw error when using json.decode() inside products provider
return showDialog(
         context: context,
         builder: (ctx) => AlertDialog(
           title: Text('An error occurred!'),
           content: Text('Something went wrong.'),
           actions: <Widget>[
             FlatButton(
               child: Text('Okay'),
               onPressed: () {
                 Navigator.of(ctx).pop();
               },
             )
           ],
         ),
       ).then((value) => null);

the above then((value) => null ); will solve your problem, it would help you i think.

The then block will run after the main Future; it won't run after catchError . If you want to run a piece of code after catchError , use a whenComplete block.

  Provider.of<Products>(context, listen: false)
          .addProduct(_editedProduct)
          .catchError((error) {
        return showDialog(
          context: context,
          builder: (ctx) => AlertDialog(
            title: Text('An error occurred!'),
            content: Text('Something went wrong.'),
            actions: <Widget>[
              FlatButton(
                child: Text('Okay'),
                onPressed: () {
                  Navigator.of(ctx).pop();
                },
              )
            ],
          ),
        );
      }).whenComplete(() { // This will run after execution
        print('after catch accoured');
        setState(() {
          _isLoading = false;
        });
        Navigator.of(context).pop();
      });
    }
  }

Below code should solve your issue. moving then statement after show dialog would make it work again.

    Provider.of<Products>(context, listen: false)
        .addProduct(_editedProduct)
        .catchError((error) {
      return showDialog(
        context: context,
        builder: (ctx) =>
            AlertDialog(
              title: Text('An error occurred!'),
              content: Text('Something went wrong.'),
              actions: <Widget>[
                FlatButton(
                  child: Text('Okay'),
                  onPressed: () {
                    Navigator.of(ctx).pop();
                  },
                )
              ],
            ),
      ).then((_) {
        print('after catch accoured');
        setState(() {
          isLoading = false;
        });
        Navigator.of(context).pop();
      });;
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM