如何在Flutter中使用Bloc模式进行错误处理?

lo_*_*_tp 15 error-handling reactive-programming reactiveui flutter

想象一下我正在使用集团来处理网络请求。如果请求失败,则根据平台的不同,处理失败的方法也会有所不同。在我的Web应用程序上,我想将用户重定向到错误页面,而在IOS应用程序上,我想显示一个对话框。

由于仅应使用bloc并共享它来处理业务逻辑,并且错误处理部分与业务逻辑无关,因此,我们应该请UI部分照顾错误处理。

UI可以将错误回调发送到块,并且当发生错误时,块将运行它。我们还可以通过在不同平台上发送不同的回调,以特定于平台的方式处理错误。

接下来是我的两个问题:

有没有更合适的方法可以做到这一点?

如何将回调发送到集团?

在flutter中,我们只能在initState生命周期方法之后访问bloc (因为我们是从builder上下文中获取bloc的,而后者仅在之后initState)。然后,我们只能在build方法中发送回调。

这样,每次重建时,我们都会重复向回调发送bloc(这些重复没有意义)。使用react,可以在生命周期(例如)中完成一次一次性初始化componentDidMount。在颤振中,我们如何达到只运行一次初始化的目标?

LgF*_*nco 3

这就是我们团队的处理方式:

首先,我们像这样构建主页(导航根):

  @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(
   ...
Run Code Online (Sandbox Code Playgroud)

我们这样声明_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;
          });
        });
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

在我们的街区,我们有:


  @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);
    }
  }

Run Code Online (Sandbox Code Playgroud)

在我们的错误处理(在主页上)中,它InfoDialog只是一个showDialog(来自 Flutter),它位于任何路由之上。因此,只需在根路由上调用警报即可。