Marco Coelho
Marco Coelho

Reputation: 433

How do I pass up (in the method stack) an Exception in Flutter?

I'm trying to make an REST app that uses "HTTP Get" communication to login in Flutter. While I had no problem importing "http/http.dart" package and running the http class methods, I encountered a problem with exception handling in Dart/Flutter. I created a method to call http, but if the connectivity is down for any reason, it will naturally return a "SocketException" exception. I have no problem handling the exception in the same method who made the get request, but if I try to pass it up in the caller method stack to the parent method, I just can't catch it again. I found the "rethrow" keyword, but so far, had no success in rethrowing the exception. Below are some methods I use in my code, both the login method and the caller method:

static Future<JsonEnvelop> loginUser(String email, String passwd) async {

    List<int> content = Utf8Encoder().convert(passwd);
    crypto.Digest digest = crypto.md5.convert(content);

    String url = _baseUrl + _loginUrl + email + "/" + digest.toString();

    http.Response response;
    try {
      response = await http.get(url);
    } on SocketException catch(e) {
      rethrow;
    }

    if(response != null && response.statusCode == 200) {
      return JsonEnvelop.fromJson(json.decode(response.body));
    } else {
      throw Exception('Failed to login');
    }
  }

void onVerifyCodeBtnPressed(BuildContext context) {
    if (_formKey.currentState.validate()) {
      String email = _emailController.text;
      String passwd = _passwdController.text;

      Future<JsonEnvelop> envelop;
      try {
        envelop = RemoteUserServices.loginUser(
            email, passwd);
      } on SocketException {
        throw Exception('Internet is down');
      }
      Scaffold.of(context).showSnackBar(SnackBar(content: Text('Login to your account')));

      envelop.then((JsonEnvelop envelop) {
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: new Text("Login"),
              content: new Text("Login Successful"),
              actions: <Widget>[
                new FlatButton(
                  child: new Text("OK"),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                )
              ],
            );
          }
        );
      });
    } else {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: new Text("Missing data"),
            content: new Text("Type your email and password in the fields"),
            actions: <Widget>[
              new FlatButton(
                child: new Text("OK"),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              )
            ],
          );
        }
      );
    }
  }

What could be the problem in this situation? I hope to create a dialog box warning the user the internet is down.

Upvotes: 9

Views: 3919

Answers (2)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657238

try/catch with exceptions from async code works only in functions with async, otherwise you'd need to pass onError callbacks or use .catchError(...) on the returned Future which is notably more difficult to get right.

  void onVerifyCodeBtnPressed(BuildContext context) async { // added async 
    if (_formKey.currentState.validate()) {
      String email = _emailController.text;
      String passwd = _passwdController.text;

      Future<JsonEnvelop> envelop;
      try {
        envelop = await RemoteUserServices.loginUser( // added `await`
            email, passwd);
      } on SocketException {
        throw Exception('Internet is down');
      }

Upvotes: 6

Filled Stacks
Filled Stacks

Reputation: 4346

Instead of using rethrow or throwing a new exception. return a Future.error()

Future<bool> methodThatErrorsOnCall() {
 return Future.error();
}
...
...
methodThatErrorsOnCall.catchError((e) {
  print('I want to show a dialog: ${e.error}');     // callback fires.
  return false;                                     // Future completes with false
})

Upvotes: 4

Related Questions