Flutter全路由网络检测问题:恢复连接后路由加载异常
问题分析
你遇到的核心问题是:InternetConnectionWrapper 在网络恢复时可能触发了 MaterialApp 子树的重建,导致 initialRoute 的同步判断逻辑再次执行——而此时如果 userData 的状态没有实时更新,或者导航栈状态被重置,就会出现路由跳转错误。
解决方案
要实现「断网时显示提示、恢复后回到原活跃路由」的需求,需要从两个核心点调整:
- 将初始路由的异步判断逻辑从
MaterialApp中剥离,避免重建时重复执行错误判断; - 优化网络监听组件的实现,确保网络恢复时保留原导航栈状态。
步骤1:用启动页处理初始路由判断
创建一个启动页(SplashScreen),仅在APP首次启动时执行 SharedPrefs 检查和路由跳转,避免网络恢复时重复触发初始路由逻辑:
class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @override State<SplashScreen> createState() => _SplashScreenState(); } class _SplashScreenState extends State<SplashScreen> { @override void initState() { super.initState(); _navigateToInitialRoute(); } Future<void> _navigateToInitialRoute() async { // 异步获取SharedPrefs中的userData(替换成你实际的读取逻辑) final userData = await _getUserDataFromSharedPrefs(); String targetRoute; if (userData.isNotEmpty) { targetRoute = userData[userType_index] == "user" ? entryPointRoute : dashboardLauncherScreenRoute; } else { targetRoute = kIsWeb ? loginScreenRoute : onboardingScreenRoute; } // 确保组件未销毁时执行跳转,替换当前启动页 if (mounted) { Navigator.pushReplacementNamed(context, targetRoute); } } // 模拟SharedPrefs读取方法,替换成你的实际实现 Future<List<String>> _getUserDataFromSharedPrefs() async { final prefs = await SharedPreferences.getInstance(); return prefs.getStringList('userData') ?? []; } @override Widget build(BuildContext context) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } }
步骤2:修改MaterialApp配置
将 initialRoute 设置为启动页,确保初始判断只执行一次:
return MaterialApp( debugShowCheckedModeBanner: false, builder: (_, child) => InternetConnectionWrapper(child: child!), title: 'X', theme: darkTheme(context), navigatorKey: navigatorKey, routes: { // 添加启动页路由 '/splash': (context) => const SplashScreen(), // 原有路由保留 entryPointRoute: (context) => const EntryPointScreen(), dashboardLauncherScreenRoute: (context) => const DashboardLauncherScreen(), loginScreenRoute: (context) => const LoginScreen(), onboardingScreenRoute: (context) => const OnboardingScreen(), }, initialRoute: '/splash', );
步骤3:优化InternetConnectionWrapper
调整网络监听组件的逻辑,断网时仅覆盖显示断页,网络恢复时直接恢复原导航栈,不重置路由:
class InternetConnectionWrapper extends StatefulWidget { final Widget child; const InternetConnectionWrapper({super.key, required this.child}); @override State<InternetConnectionWrapper> createState() => _InternetConnectionWrapperState(); } class _InternetConnectionWrapperState extends State<InternetConnectionWrapper> { bool _hasInternet = true; late StreamSubscription<ConnectivityResult> _connectivitySubscription; @override void initState() { super.initState(); _checkInitialConnectivity(); // 监听网络状态变化 _connectivitySubscription = Connectivity().onConnectivityChanged.listen((result) { setState(() { _hasInternet = result != ConnectivityResult.none; }); }); } Future<void> _checkInitialConnectivity() async { final result = await Connectivity().checkConnectivity(); setState(() { _hasInternet = result != ConnectivityResult.none; }); } @override void dispose() { _connectivitySubscription.cancel(); super.dispose(); } @override Widget build(BuildContext context) { if (!_hasInternet) { // 断网时显示提示页,不替换原导航栈 return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text("无网络连接,请检查网络设置"), const SizedBox(height: 16), ElevatedButton( onPressed: _checkInitialConnectivity, child: const Text("重试连接"), ), ], ), ), ); } // 网络正常时直接返回原页面树,保留导航栈状态 return widget.child; } }
关键说明
- 启动页的异步判断仅在APP首次启动时执行,网络恢复时不会重新触发,避免了基于旧状态的错误跳转;
InternetConnectionWrapper仅在断网时覆盖显示提示,网络恢复时直接恢复原导航栈,确保回到断网前的活跃路由;- 避免在
MaterialApp的initialRoute中做异步状态判断,因为initialRoute是同步属性,异步数据未加载完成时会导致初始路由错误。
内容的提问来源于stack exchange,提问作者Roberto
相关产品推荐
相关产品推荐

