This is how we handle it in my team:
First we build our main page (The navigation root) like this:
@override
Widget build(BuildContext context) {
return BlocBuilder<SuspectEvent, SuspectState>(
bloc: _bloc,
builder: (context, state) {
if (state.cameras.isEmpty) _bloc.dispatch(GetCamerasEvent());
if (!_isExceptionHandled) {
_shouldHandleException(
hasException: state.hasException,
handleException: state.handleException);
}
return Scaffold(
...
We declare the _shouldHandleException
like this (still on the main page):
_shouldHandleException(
{@required bool hasException, @required Exception handleException}) {
if (hasException) {
if (handleException is AuthenticationException) {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.error,
text: 'Please, do your login again.',
title: 'Session expired')
.then((val) {
Navigator.popUntil(context, ModalRoute.withName("https://stackoverflow.com/"));
this._showLogin();
});
});
} else if (handleException is BusinessException) {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.alert,
text: handleException.toString(),
title: 'Verify your fields')
.then((val) {
_bloc.dispatch(CleanExceptionEvent());
_isExceptionHandled = false;
});
});
} else {
_isExceptionHandled = true;
SchedulerBinding.instance.addPostFrameCallback((_) async {
InfoDialog.showMessage(
context: context,
infoDialogType: DialogType.error,
text: handleException.toString(),
title: 'Error on request')
.then((val) {
_bloc.dispatch(CleanExceptionEvent());
_isExceptionHandled = false;
});
});
}
}
}
On our block we have:
@override
Stream<SuspectState> mapEventToState(SuspectEvent event) async* {
try {
if (event is GetCamerasEvent) {
... //(our logic)
yield (SuspectState.newValue(state: currentState)
..cameras = _cameras
..suspects = _suspects);
}
... //(other events)
} catch (error) {
yield (SuspectState.newValue(state: currentState)
..hasException = true
..handleException = error);
}
}
In our error handling (on main page) the InfoDialog
is just a showDialog
(from Flutter) and it gets on top of any route. So the alert just needed to be called on the root route.