Как сделать обработку ошибок с шаблоном блока во флаттере? - PullRequest
0 голосов
/ 05 октября 2018

Представьте, что я использую блок для обработки сетевого запроса.В случае сбоя запроса способ обработки сбоя будет различным в зависимости от платформы.В моем веб-приложении я хотел бы перенаправить пользователя на страницу с ошибкой, в то время как в моем приложении IOS я хотел бы показать диалоговое окно.

Поскольку блок должен использоваться и использоваться только для обработки бизнес-логики, аЧасть обработки ошибок не имеет ничего общего с бизнес-логикой, мы должны попросить часть пользовательского интерфейса позаботиться об обработке ошибок.

Пользовательский интерфейс может отправить обратный вызов ошибки в блок, и блок будет запускать его при возникновении ошибки.,Мы также можем обработать ошибку в зависимости от платформы, отправив различные обратные вызовы на разных платформах.

Тогда возникает два моих вопроса:

Есть ли более подходящий способ сделать это?

Как отправить обратный вызов в блок?

В флаттере у нас есть доступ к блоку только после метода жизненного цикла initState (поскольку мы получаем блок из контекста компоновщика, который следует только после initState).Тогда мы можем только отправить обратный вызов в методе сборки.

Таким образом, мы будем повторно отправлять обратный вызов в блок каждый раз, когда происходит восстановление (эти повторения не имеют смысла).С помощью реакции такая однократная инициализация может выполняться в таких жизненных циклах, как componentDidMount.Во флаттере, как нам достичь цели, чтобы выполнить эти инициализации только один раз?

1 Ответ

0 голосов
/ 15 июля 2019

Вот как мы справляемся с этим в моей команде:

Сначала мы создаем нашу главную страницу (корень навигации) следующим образом:

  @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 (от Флаттера), и он попадает в начало любого маршрута.Так что оповещение просто необходимо вызвать на корневом маршруте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...