web-dev-qa-db-ja.com

Flutter BLoC:StreamBuilderのbuild()メソッドのNavigator.pop

私はBLoCパターンに従ってストリームをサブスクライブし、ビルドメソッドの状態変化に対応しています。データが読み込まれたら、画面を閉じます。

_  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Bloc'),
      ),
      body: SafeArea(
        child: StreamBuilder<UserState>(
          stream: _userBloc.user,
          initialData: UserInitState(),
          builder: (context, snapshot) {
            if (snapshot.data is UserInitState) {
              return _buildInit();
            }
            if (snapshot.data is UserDataState) {
              Navigator.pop(context, true);
              return Container();
            }
            if (snapshot.data is UserLoadingState) {
              return _buildLoading();
            }
          },
        ),
      ),
    );
  } 
_

Navigator.pop(context, true);メソッドでbuild()を実行すると、次のようになります。

_I/flutter ( 4360): ══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 4360): The following assertion was thrown while notifying status listeners for AnimationController:
I/flutter ( 4360): setState() or markNeedsBuild() called during build.
I/flutter ( 4360): This Overlay widget cannot be marked as needing to build because the framework is already in the
I/flutter ( 4360): process of building widgets. A widget can be marked as needing to be built during the build phase
I/flutter ( 4360): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter ( 4360): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter ( 4360): Otherwise, the framework might not visit this widget during this build phase.
_

BLoCパターンでそのようなケースを処理する正しい方法は何ですか?

私が思いついた解決策の1つは、initState()でストリームのリスニングを開始することです。この場合、2人のサブスクライバーがいるため、ストリームをbroadcast()する必要があります。

これに対するより良い解決策はありますか?

6

次の3つの解決策が考えられます。

1)ウィジェットを再構成するのが最善のようです。私が見る限りでは、「ロード画面」が必要です。これが別のウィジェットではなく、独自のナビゲーション項目である必要がある理由はわかりません。

つまり。 StreamBuilderをプッシュできますか?レベルアップするので、あなたのビルダーメソッドは次のようになります:

_if (!snapshot.hasData) {
  return LoadingScreen(snapshot);
}
// Whatever you do with your data.
_

2)私は個人的にStatefulWidgetを作成し、initState()でストリームを手動でリッスンし、setState()を手動で呼び出すと思います。 StreamBuilderは不要

3)クレイジーな回避策として、おそらくビルダーでFuture(() { Navigator.of(context).pop(); });を使用できます。 (ビルダーではなく、contextメソッドのbuildを使用する必要がある可能性があります。しかし、とにかくその解決策はお勧めしません)

0
herbert