Flutter go_router 6.0.1:ShellRoute下返回键触发空安全错误
解决ShellRoute实现底部导航时返回键触发的空安全错误
这种空安全错误本质是GoRouter在处理返回操作时,ShellRoute的内部路由状态出现了空值访问,而WillPopScope的拦截时机晚于GoRouter内部的路由状态检查,所以无法阻止错误触发。以下是几种可行的解决思路:
1. 自定义导航拦截逻辑,提前处理子路由返回
通过navigatorBuilder在GoRouter的根层级添加拦截,优先处理ShellRoute子路由栈的返回,避免GoRouter直接访问空状态:
final GoRouter router = GoRouter( navigatorBuilder: (context, state, child) { return WillPopScope( onWillPop: () async { // 获取当前ShellRoute的状态 final shellState = ShellRouteState.of(context); if (shellState?.shellContext != null) { final subNavigator = Navigator.of(shellState!.shellContext!); // 如果子路由栈可以返回,优先处理子栈pop if (subNavigator.canPop()) { subNavigator.pop(); return false; // 阻止GoRouter执行默认的全局pop逻辑 } } // 子栈无法返回时,再处理全局路由的pop return router.canPop(); }, child: child, ); }, routes: [ ShellRoute( builder: (context, state, child) => BottomNavigationBar( currentIndex: selectedIndex, onTap: (idx) { // 切换标签页使用go方法,避免栈堆积 idx == 0 ? router.go('/') : router.go('/settings'); }, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'), BottomNavigationBarItem(icon: Icon(Icons.settings), label: '设置'), ], ), routes: [ GoRoute(path: '/', builder: (_, __) => const HomePage()), GoRoute(path: '/settings', builder: (_, __) => const SettingsPage()), ], ), ], );
2. 重写GoRouterDelegate的popRoute方法
如果需要更底层的控制,可以自定义GoRouterDelegate,在popRoute方法中先检查路由状态的有效性,再执行pop操作:
class CustomRouterDelegate extends GoRouterDelegate { CustomRouterDelegate({required super.configuration}); @override Future<bool> popRoute() async { final context = navigatorKey.currentContext; if (context == null) return false; // 检查ShellRoute的子导航栈 final shellState = ShellRouteState.of(context); if (shellState?.shellContext != null) { final subNavigator = Navigator.of(shellState!.shellContext!); if (subNavigator.canPop()) { subNavigator.pop(); return Future.value(true); } } // 全局路由栈可pop时,执行默认逻辑 return canPop() ? super.popRoute() : Future.value(false); } }
然后在初始化GoRouter时使用自定义Delegate:
final GoRouter router = GoRouter( routerDelegate: CustomRouterDelegate( configuration: GoRouterConfiguration(routes: [...]), ), // 其他配置项 );
3. 规范路由切换逻辑
切换底部导航标签时,使用go方法而非push,避免子路由栈堆积导致返回时出现异常的空状态。确保每个标签页对应的路由是单例栈,而非多层栈。
内容的提问来源于stack exchange,提问作者Zelkreps
相关产品推荐
相关产品推荐

