Вот как мы справляемся с этим в моей команде:
Сначала мы создаем нашу главную страницу (корень навигации) следующим образом:
@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(
...
Мы объявляем _shouldHandleException
вот так(все еще на главной странице):
_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('/'));
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;
});
});
}
}
}
В нашем блоке мы имеем:
@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);
}
}
В нашей обработке ошибок (на главной странице) InfoDialog
это просто showDialog
(от Флаттера), и он попадает в начало любого маршрута.Так что оповещение просто необходимо вызвать на корневом маршруте.