How to do error handling with bloc pattern in flutter? How to do error handling with bloc pattern in flutter? flutter flutter

How to do error handling with bloc pattern in flutter?


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('/'));            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.


You can access the BLoC in the initState method if you wrap it in a scheduleMicrotask method, so that it runs after the initState method completed:

@overridevoid initState() {  super.initState();  // Do initialization here.  scheduleMicrotask(() {    // Do stuff that uses the BLoC here.  });}

You can also check out this answer to a different question outlining the Simple BLoC pattern, which just calls asynchronous methods directly on the BLoC instead of putting events into sinks.

That would allow code like this:

Future<void> login() {  try {    // Do the network stuff, like logging the user in or whatever.    Bloc.of(context).login(userController.text, emailController.text);  } on ServerNotReachableException {    // Redirect the user, display a prompt or change this    // widget's state to display an error. It's up to you.  }}


You can use superEnum package to create states and events for a Bloc.(and here you will declare a state for the Error by doing this :

  @Data(fields: [DataField<Error>('error')])  OrderLoadingFailedState,

(If anyone need an example of how to use it, please tell me i will show you an example)