Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do error handling with bloc pattern in flutter?

Imagine I'm using a bloc to handle a network request. If the request fails, the way to handle the failure would be different depending on the platform. On my web app, I would like to redirect the user to an error page while on my IOS app I would like to show a dialog.

As bloc should only be used and shared to handle the business logic, and the error handling part has nothing to do with the business logic, we should ask the UI part to take care of the error handling.

The UI can send error callback to the bloc and the bloc will run it when an error happens. We can also handle the error in a platform-specific way by sending different callbacks in different platforms.

Then there come my two questions:

Is there a more appropriate way to do this?

How to send the callback to the bloc?

In flutter, we only have access to bloc after the initState life cycle method(for we get bloc from builder context, which only comes after initState). Then we can only send callback in the build method.

In this way, we will repetitively send callback to bloc every time rebuilding happens(these repetitions make no sense). With react, such one-time initialization could be done in life cycles such as componentDidMount. In flutter how do we reach the goal of running these initialization only once?

like image 210
lo__tp Avatar asked Oct 05 '18 01:10

lo__tp


People also ask

How do you handle errors in Flutter?

Errors that don't occur within Flutter's callbacks can't be caught by the framework, but you can handle them by setting up a Zone . All errors caught by Flutter are routed to the FlutterError. onError handler. By default, this calls FlutterError.

How does BLoC work in Flutter?

The UI/Flutter layer can only talk to the BLoC layer. The BLoC layer receives input events, processes business logic using the data layer and responds with output events to the UI layers or other listeners. This structure can scale nicely as the app grows.

Why should I use BLoC pattern Flutter?

Bloc is a good pattern that will be suitable for almost all types of apps. It helps improve the code's quality and makes handling states in the app much more manageable. It might be challenging for someone who is just beginning to use Flutter because it uses advanced techniques like Stream and Reactive Programming.


1 Answers

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.

like image 128
LgFranco Avatar answered Sep 20 '22 04:09

LgFranco