Reputation: 433
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
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
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