使用Auto_Route与BlocListener显示弹窗时遇Navigator上下文错误求助
问题分析与解决方案
错误原因
你遇到的Navigator operation requested with a context that does not include a Navigator错误,核心原因是当前BlocListener使用的上下文是MaterialApp.router的父级上下文,而Navigator是MaterialApp内部初始化的组件,父级上下文无法访问到它,所以调用showCupertinoDialog时会报错。
修复方案
调整组件嵌套结构,将BlocListener移到MaterialApp.router的子树中,确保它能获取到包含Navigator的上下文。具体可以通过MaterialApp.router的builder属性来实现:
class AppWidget extends StatelessWidget { AppWidget({super.key}); final GlobalKey<ScaffoldMessengerState> messengerKey = GlobalKey<ScaffoldMessengerState>(); // 用于防止重复弹窗的标记 bool _isDialogShown = false; @override Widget build(BuildContext context) { return RepositoryProvider( create: (_) => getIt<CPlusNetworkRepository>(), child: BlocProvider( create: (_) => getIt<ConnectionStatusBloc>() ..add(const StreamSubsricptionRequested()), child: MaterialApp.router( scaffoldMessengerKey: messengerKey, routeInformationParser: appRouter.defaultRouteParser(), routerDelegate: appRouter.delegate(), // 通过builder将BlocListener嵌入MaterialApp子树 builder: (context, child) { return BlocListener<ConnectionStatusBloc, ConnectionStatusState>( listener: (context, state) { state.map( connected: (_) { // 网络恢复时关闭弹窗并重置标记 if (_isDialogShown) { Navigator.of(context).pop(); _isDialogShown = false; } }, disconnected: (_) async { // 避免重复弹出弹窗 if (!_isDialogShown) { _isDialogShown = true; await showCupertinoDialog( context: context, builder: (context) => const CupertinoAlertDialog( title: Text('Alert'), content: Text('Please switch on Wifi/Mobile Data'), ), ); _isDialogShown = false; } }, unknown: (_) {}, ); }, child: child, ); }, ), ), ); } }
额外优化说明
- 添加了
_isDialogShown标记,避免网络状态反复切换时弹出多个重复弹窗; - 网络恢复时自动关闭弹窗,提升用户体验;
- 通过
MaterialApp.router的builder属性,确保BlocListener的上下文能访问到Navigator,从根源解决上下文错误问题。
内容的提问来源于stack exchange,提问作者Horacio Vásquez
相关产品推荐
相关产品推荐

