1. The Problem
I'm using a try-catch-finally
1 dynamic to deal with exception handling for Firebase in my simple authentication package for my app. In it, when I receive an error from Firebase's authentication service, I update the labelText
on the (custom) TextFormField
to show the user that an error occurred.
However, notifyListeners()
is apparently being run concurrently to the catch
clause, causing the rebuilds to not happen synchronously with exception-handling.
Currently, I'm using ChangeNotifierProvider
for basically everything, but should I change to a FutureProvider
dynamic. If so, what's the best way of doing it?
1 I did try using then-catchError-whenComplete
also.
2. The Code
2.1 The Complete Code (Optional)
The complete code is a bit long at this point in the project, but I think that what's shown below will suffice.
At any rate, if you want to check everything out, the whole project is available: flutter_firebase_auth_benchmark.
The relevant files are:
firebase_auth.dart
: theprovider
class with the relevant data.login_screen.dart
: theemail_field
is fed withprovider
data with theConsumer
widget.password_reset_workflow.dart
: the button that calls the relevant method is put into theLoginScreen
through anAnimatedSwitcher
.
2.2 The Provider Class
I'm having to use Future.delayed
in order to manually synchronize the notifyListeners()
and the build()
methods — I know, I know, it's very bad...
class Auth extends ChangeNotifier {
String _errorMsg;
String get errorMsg => _errorMsg;
...
Future<void> sendPasswordResetWithEmail({@required String email}) async {
try {
await FirebaseAuth.instance.sendPasswordResetEmail(email: email);
} catch(e) {
switch (e.code) {
case 'ERROR_USER_NOT_FOUND':
_errorMsg = 'user not found';
break;
default:
throw UnknownPasswordResetError(
'Unknown error for password reset with Firebase.');
}
} finally {
notifyListeners();
await Future.delayed(Duration(milliseconds: 10));
}
}
}
2.3 My Custom TextFormField
Widget
Something like this is in the app:
return Consumer<Auth>(
builder: (context, auth, _) {
return AuthTextFormField(
...,
errorMsgFromServer: auth.errorMsg,
);
}
);
Lastly, a validation button uses formKey.currentState.validate()
in an if
clause to trigger asynchronously await auth.sendPasswordResetWithEmail
.