问题描述
我正在使用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));
}),);