0

我将描述我的问题和我遇到的错误。然后我将复制我的代码以使其更清晰。问题为:

  • 我在根小部件(StartupScreen)上使用 MultiBlocProvider,声明的 2 个块是 AuthenticationBloc、ApplicationBloc。
  • BlocListener<AuthenticationBloc, AuthenticationState>在根小部件 (StartupScreen) 处使用。
  • 如果 AuthenticationBloc 的状态更改为 AuthAuthenticatedState,则路由到 MainScreen,否则路由到 LoginScreen。
  • 如果用户已登录,则路由到 MainScreen:
    1. 我将从存储中(异步)获取 currentUser,然后将 BlocListener 包装在 FutureBuilder 中。它最终无法显示屏幕并出现以下错误:
BlocProvider.of() called with a context that does not contain a Bloc of type ApplicationBloc.

No ancestor could be found starting from the context that was passed to BlocProvider.of<ApplicationBloc>().

This can happen if the context you used comes from a widget above the BlocProvider.

The context used was: BlocListener<ApplicationBloc, ApplicationState>(dirty, state: _BlocListenerBaseState<ApplicationBloc, ApplicationState>#1abf7(lifecycle state: created))

The relevant error-causing widget was
    FutureBuilder<UserCredentials>                       package:my_app/…/ui/main_screen.dart:43

When the exception was thrown, this was the stack
#0      BlocProvider.of                                  package:flutter_bloc/src/bloc_provider.dart:106
#1      _BlocListenerBaseState.initState                 package:flutter_bloc/src/bloc_listener.dart:160
#2      StatefulElement._firstBuild                      package:flutter/…/widgets/framework.dart:4355
#3      ComponentElement.mount                           package:flutter/…/widgets/framework.dart:4201
#4      SingleChildWidgetElementMixin.mount              package:nested/nested.dart:223
...


StartupScreen.dart

class StartupScreen extends StatelessWidget {
  final ApplicationBloc appBloc;
  final AuthenticationBloc authBloc;

  StartupScreen(this.appBloc, this.authBloc) : super();

  @override
  Widget build(BuildContext context) {
    ScreenSizeConfig().init(context);
    authBloc.add(AuthStartedEvent());

    return MultiBlocProvider(
      providers: [
        BlocProvider<ApplicationBloc>(
          create: (context) => appBloc,
        ),
        BlocProvider<AuthenticationBloc>(
          create: (context) => authBloc,
        ),
      ],
      child: BlocListener<AuthenticationBloc, AuthenticationState>(
        listener: (context, state) {
          if (state is AuthUnauthenticatedState) {
            Navigator.of(context).pushReplacementNamed(RouteConstants.LOGIN_SCREEN);
          } else if (state is AuthAuthenticatedState) {
            Navigator.of(context).pushReplacementNamed(RouteConstants.MAIN_SCREEN);
          }
        },
        child: BlocBuilder<AuthenticationBloc, AuthenticationState>(
          builder: (context, state) {
            return Center(
              child: Container(
                child: Text('Startup Screen'),
              ),
            );
          },
        ),
      ),
    );
  }
}


主屏幕.dart

class MainScreen extends StatelessWidget {
  final ApplicationBloc appBloc;
  final AuthenticationBloc authBloc;

  MainScreen(this.appBloc, this.authBloc) : super();

  @override
  Widget build(BuildContext context) {
    return _MainPageWidget(appBloc, authBloc);
  }
}

class _MainPageWidget extends StatefulWidget {
  final ApplicationBlocappBloc;
  final AuthenticationBloc authBloc;

  _MainPageWidget(this.appBloc, this.authBloc) : super();

  @override
  State<StatefulWidget> createState() => _MainPageState();
}

class _MainPageState extends State<_MainPageWidget> {
  Future<UserCredentials> getUserCredentials() async {
    return await widget.appBloc.authService.getUser();
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<UserCredentials>(
        future: getUserCredentials(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Center(
              child: CircularProgressIndicator(),
            );
          } else {
            return _buildBlocListener(snapshot.data);
          }
        });
  }

  Widget _buildBlocListener(UserCredentials userCredentials) {
    return BlocListener<ApplicationBloc, ApplicationState>(
      listener: (context, state) {
        if (userCredentials.isNewUser) {
          widget.appBloc.add(AppNewUserEvent());
        } else {
          widget.appBloc
              .add(AppAlreadyCompletedNewUserProcessEvent());
        }
      },
      child: _buildBlocBuilder(context, widget.appBloc),
    );
  }

  Widget _buildBlocBuilder(BuildContext context, ApplicationBloc appBloc) {
    return BlocBuilder<ApplicationBloc, ApplicationState>(
      builder: (context, state) {
        print('main_screen.dart: go to mainscreen BlocBuilder builder: state: $state');
        return Container(
          child: Text('Main Screen'),
        );
      },
    );
  }
}

4

1 回答 1

1

从 bloc 库的文档中:

您不能从提供它的同一上下文访问一个块,因此您必须确保在子 BuildContext 中调用 BlocProvider.of()

https://bloclibrary.dev/#/faqs?id=blocproviderof-fails-to-find-bloc

您必须取出 BlocListener 并将其放在单独的小部件中,或者使用构建器小部件包装您的 BlocListener。

于 2020-04-12T07:21:30.087 回答