web-dev-qa-db-ja.com

フラッターのブロックパターンでエラー処理を行う方法は?

ネットワーク要求を処理するためにブロックを使用していると想像してください。リクエストが失敗した場合、失敗の処理方法はプラットフォームによって異なります。私のWebアプリで、ユーザーをエラーページにリダイレクトしたいのですが、IOSアプリでダイアログを表示したいと思います。

Blocはビジネスロジックを処理するためにのみ使用および共有する必要があり、エラー処理部分はビジネスロジックとは何の関係もないため、UI部分にエラー処理を処理するよう依頼する必要があります。

UIはエラーコールバックをブロックに送信でき、ブロックはエラーが発生したときにそれを実行します。異なるプラットフォームで異なるコールバックを送信することにより、プラットフォーム固有の方法でエラーを処理することもできます。

次に、私の2つの質問があります。

これを行うより適切な方法はありますか?

コールバックをブロックに送信する方法は?

Flutterでは、initStateライフサイクルメソッドの後でのみblocにアクセスできます(initStateの後にのみ来るビルダーコンテキストからblocを取得するため)。その後、buildメソッドでのみコールバックを送信できます。

このようにして、再構築が行われるたびにブロックにコールバックを繰り返し送信します(これらの繰り返しは意味がありません)。 reactを使用すると、componentDidMountなどのライフサイクルでこのような1回限りの初期化を実行できます。フラッターでは、これらの初期化を一度だけ実行するという目標にどのように到達しますか?

18
lo__tp

これが私のチームでの処理方法です。

まず、次のようにメインページ(ナビゲーションルート)を作成します。

  @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は(Flutterからの)showDialogにすぎず、どのルートよりも優先されます。したがって、ルートルートでアラートを呼び出す必要があるだけです。

1
LgFranco

initStateメソッドでBLoCをラップすると、scheduleMicrotaskメソッドでBLoCにアクセスできるため、initStateメソッドの完了後にBLoCが実行されます。

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

また、チェックアウト 別の質問に対するこの回答 単純なBLoCパターンの概要を示しています。これは、イベントをシンクに配置する代わりに、BLoCで非同期メソッドを直接呼び出すだけです。

それはこのようなコードを許可します:

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.
  }
}
0
Marcel