Flutter跳转MainGameScreen报找不到Provider<AuthBloc>错误如何解决
错误触发原因
- Provider的查找逻辑是沿着当前Widget树向上查找父节点中注册的对应类型Provider实例,只有目标Widget的父链上存在已注册的对应Provider时才能正常读取
- 你的
AuthBlocProvider注册在当前路由页面的子树中,而非全局的MaterialApp层级,当通过Navigator.push打开新的MainGameScreen页面时,新页面的Widget树和当前页面子树平级挂载在MaterialApp下,无法访问到当前页面子树内的AuthBloc - 弹窗
builder参数返回的是独立的子树,如果你在跳转时误用了弹窗的局部Context,也会缩小Provider的查找范围,导致无法找到上层注册的AuthBloc
修复方案
你可以根据业务场景选择以下任意一种方案:
- 方案1:将
AuthBloc提升到全局注册
将AuthBloc的Provider注册逻辑移动到MaterialApp的上层,所有路由页面都可以直接访问到全局的AuthBloc实例,示例代码如下:
void main() { runApp( BlocProvider( create: (context) => AuthBloc(), child: MyApp(), ), ); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( // 保留原有应用配置 ); } }
- 方案2:跳转时手动传递
AuthBloc实例
如果你不需要全局共享AuthBloc,可以在跳转前用原始页面的Context提前获取到AuthBloc实例,再通过BlocProvider.value挂载到新页面的上层,修改后的quitGame代码如下:
Widget quitGame(BuildContext context) { // 在弹窗外部用原始页面Context提前获取AuthBloc实例 final authBloc = context.read<AuthBloc>(); showDialog( context: context, // 重命名builder的Context避免混淆 builder: (BuildContext dialogContext) { return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), elevation: 0, backgroundColor: Colors.transparent, child: Stack( children: <Widget>[ Container( padding: EdgeInsets.only(left: 20, top: 30, right: 20, bottom: 20), margin: EdgeInsets.only(top: 45), decoration: BoxDecoration( shape: BoxShape.rectangle, color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black, offset: Offset(0, 10), blurRadius: 10), ]), child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Text( "QUIT GAME", textScaleFactor: 1, style: TextStyle( fontSize: 40, fontWeight: FontWeight.w600), ), SizedBox( height: 15, ), Text( "Are you sure you want to leave the game?", textScaleFactor: 1, style: TextStyle(fontSize: 14), textAlign: TextAlign.center, ), SizedBox( height: 10, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Align( alignment: Alignment.bottomCenter, child: ElevatedButton( style: ElevatedButton.styleFrom( primary: Color(0xFFec4688), ), onPressed: () { Navigator.of(dialogContext).pop(); }, child: Text("NO", textScaleFactor: 1, style: TextStyle(fontSize: 20))), ), Align( alignment: Alignment.bottomCenter, child: ElevatedButton( style: ElevatedButton.styleFrom( primary: Color(0xFF1fd281), ), onPressed: () { roundTimer.cancel(); Navigator.push( context, // 使用原始页面的Context MaterialPageRoute( builder: (context) => BlocProvider.value( value: authBloc, child: MainGameScreen(), ), ), ); }, child: Text("YES", textScaleFactor: 1, style: TextStyle(fontSize: 20))), ), ], ), ], ), ), ], ), ); }); }
- 方案3:排查Context使用错误
明确区分原始页面Context和弹窗局部Context,关闭弹窗时使用弹窗的Context,跳转页面时使用quitGame方法传入的原始页面Context,避免因Context范围错误导致Provider查找失败。
内容的提问来源于stack exchange,提问作者Saad Bashir
相关产品推荐
相关产品推荐

