导航到新页面时,BLOC失去上下文

问题描述

我正在使用BLOC模式来验证我的应用程序中的用户我有一个包装我的应用程序的主BlocProvider。并根据身份验证状态进行构建。

如果用户未通过身份验证,则我具有入职/介绍屏幕,这些屏幕将导航到登录屏幕。

登录屏幕包裹在另一个BlocProvider中,该BlocProvider包含一个将进行登录的按钮,并在登录成功后添加一个登录事件。

问题是当我从入职屏幕导航时,我失去了主要的authenticationBloc上下文。按下新屏幕后,我需要什么才能访问身份验证组。

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  Bloc.observer = SimpleBlocObserver();

  runApp(
    MyApp(),);
}

class AuthenticationWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider<AuthenticationBloc>(
        create: (context) => AuthenticationBloc()..add(AppStarted()),child: MyApp(),),);
  }
}
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return BlocListener<AuthenticationBloc,AuthenticationState>(
      listener: (context,state) {
        if (state is Authenticated) {
          _appUserProfileRepository = AppUserProfileRepository();
        }
      },child: BlocBuilder<AuthenticationBloc,AuthenticationState>(
        builder: (context,state) {

          _authCredentialHelper = state.authCredentialHelper;

          if (state is Uninitialized) {
            return SplashScreen();
          }

          if (state is Unauthenticated) {
            return OnboardingScreens(authCredentialHelper: _authCredentialHelper);
          }

          if (state is InvalidRegistration) {
            return RegisterProfileScreen(authCredentialHelper: _authCredentialHelper);
          }

          if (state is Authenticated) {
              xxx
          }

          return Scaffold(body: Center(child: LoadingIndicator()));
        },);
  }
}

这是入职屏幕,导航后我会立即松开authenticationbloc上下文

class OnboardingScreens extends StatelessWidget {
  final AuthCredentialHelper authCredentialHelper;

  OnboardingScreens({this.authCredentialHelper});

  _pages(BuildContext context) {
    return [
      xxx
    ];
  }

  _getStartedClicked(BuildContext context) {
    Navigator.push(context,MaterialPageRoute(builder: (context) {
      return LoginScreen(authCredentialHelper: authCredentialHelper);
    }));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: IntroductionScreen(
          pages: _pages(context),onDone: () => _getStartedClicked(context),showSkipButton: true,done: xxx
        ),);
  }
}

在1处添加断点时,上下文可以使用BlocProvider.of(context)的有效值。

单步执行2.会给我一个错误: 使用不包含AuthenticationBloc类型的Cubit的上下文调用BlocProvider.of()。

  _getStartedClicked(BuildContext context) {
    1----->Navigator.push(context,MaterialPageRoute(builder: (context) {
    2----->return LoginScreen(authCredentialHelper: authCredentialHelper);
    }));
  }

这是LoginScreen代码

class LoginScreen extends StatelessWidget {
  final AuthCredentialHelper authCredentialHelper;

  LoginScreen({this.authCredentialHelper});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.arrow_back,color: darkBlue),onpressed: () => Navigator.of(context).pop(),backgroundColor: Colors.transparent,elevation: 0.0,body: SafeArea(
        child: Center(
          child: BlocProvider<LoginBloc>(
            create: (context) => LoginBloc(authCredentialHelper: authCredentialHelper),child: LoginForm(authCredentialHelper: authCredentialHelper),);
  }
}

出现此错误

The following assertion was thrown building _InheritedProviderScope<LoginBloc>(value: Instance of 'LoginBloc'):
BlocProvider.of() called with a context that does not contain a Cubit of type AuthenticationBloc.

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

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

解决方法

更改此内容:

   Navigator.push(context,MaterialPageRoute(builder: (context) {
      return LoginScreen(authCredentialHelper: authCredentialHelper);
   }));

   Navigator.push(
     context,MaterialPageRoute(builder: (contextLoginScreen) {
        return BlocProvider.value(
            value: context.bloc<AuthenticationBloc>(),child: LoginScreen(authCredentialHelper: authCredentialHelper));
     }),);