My firestore update function can throw an error like the following:
class GameIsNotNewestException implements Exception {
String cause;
GameIsNotNewestException(this.cause);
}
class FirebaseGamesRepository {
Future<void> updateGame(Game game) {
return Firestore.instance.runTransaction((Transaction transaction) async {
// ...
if (newestGameId != game.id) {
throw GameIsNotNewestException("Game is not the newest game");
}
// ...
});
}
}
My _mapUpdateGameToState looks like the following:
class GamesBloc extends Bloc<GamesEvent, GamesState> {
//...
@override
Stream<GamesState> mapEventToState(GamesEvent event) async* {
// ...
if (event is UpdateGame) {
yield* _mapUpdateGameToState(event);
}
}
Stream<GamesState> _mapUpdateGameToState(UpdateGame event) async* {
_gamesRepository.updateGame(event.game);
}
}
Somewhere in UI part I would like to catch that error, when I update the game:
try {
BlocProvider.of<GamesBloc>(context).add(
UpdateGame(game)
);
} on GameIsNotNewestException {
// Some error handling. However, this exception is never catched.
}
However the error is never catched. Instead I get an error like the following:
java.lang.Exception: DoTransaction failed: Instance of 'GameIsNotNewestException'
What is the proper way to handle such an error on an event like update?
Hi @zsoerenm 馃憢
The exception should be handled in the bloc itself, not within the UI, since you should always aim to keep the business logic out of the presentation layer.
So handle the exception in _mapUpdateGameToState and yield a failure state that you can use to maybe show a snackbar.
Stream<GamesState> _mapUpdateGameToState(UpdateGame event) async* {
try {
// ! you'd need to await the call to be able to catch any potential errors/exceptions with a try catch block
await _gamesRepository.updateGame(event.game);
} on GameIsNotNewestException catch (e) {
yield GamesFailure(message: e.cause);
} catch (_) {
yield GamesFailure(message: 'generic error');
}
}
If you need to both keep the UI and show a message then you can make the failure message be part of the state.
So instead of yield GamesFailure(message: e.cause); you would yield state.copyWith(message: e.cause);
You could then use a BlocListener to react to either GamesFailure or to state having a failure.
Hope that sets you on the right track 馃憤
Thank you very much. That's exactly what I was looking for.
Most helpful comment
Thank you very much. That's exactly what I was looking for.