如何通过路由全局检查Flutter应用的网络连接状态
实现Flutter全局网络连接检查方案
你的方案无效的核心原因是:onGenerateRoute在build时初始化,传入的_connectionStatus是当时的静态值,后续网络状态变化时,不会触发onGenerateRoute更新,导致路由跳转无法获取最新网络状态。以下是基于你现有代码(使用Consumer)的可行方案:
1. 用Riverpod管理全局网络状态
将网络状态从Widget的State中剥离,用全局状态管理统一维护,确保任何地方都能获取最新状态:
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'dart:developer' as developer; final connectivityProvider = StateNotifierProvider<ConnectivityNotifier, ConnectivityResult>( (ref) => ConnectivityNotifier(), ); class ConnectivityNotifier extends StateNotifier<ConnectivityResult> { final Connectivity _connectivity = Connectivity(); late StreamSubscription<ConnectivityResult> _subscription; ConnectivityNotifier() : super(ConnectivityResult.none) { _initConnectivity(); _subscription = _connectivity.onConnectivityChanged.listen((result) { state = result; }); } Future<void> _initConnectivity() async { try { final result = await _connectivity.checkConnectivity(); state = result; } on PlatformException catch (e) { developer.log('无法检查网络状态', error: e); } } @override void dispose() { _subscription.cancel(); super.dispose(); } }
2. 修改App入口,让路由生成读取最新状态
将原ConsumerStatefulWidget改为ConsumerWidget,在onGenerateRoute中传入WidgetRef,直接读取最新网络状态:
class MyProjectAppScreen extends ConsumerWidget { const MyProjectAppScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { const String appRoot = splash; return MaterialApp( title: 'My Project', theme: theme_data.ManageTheme().getTheme(context), darkTheme: theme_data.ManageTheme().getDarkTheme(context), themeMode: ThemeMode.light, initialRoute: appRoot, onGenerateRoute: (settings) => generateRoute(settings, ref), debugShowCheckedModeBanner: false, ); } }
3. 重写路由生成逻辑,加入网络检查
在generateRoute中实时读取网络状态,动态跳转页面:
Route<dynamic> generateRoute(RouteSettings settings, WidgetRef ref) { final connectivityStatus = ref.watch(connectivityProvider); // 无网络时,统一跳转到无网络页面(排除无网络页面自身) if (connectivityStatus == ConnectivityResult.none) { if (settings.name != '/no-internet') { return MaterialPageRoute( builder: (context) => const NoInternetScreen(), settings: const RouteSettings(name: '/no-internet'), ); } } else { // 网络正常时,按原有逻辑跳转目标页面 switch (settings.name) { case splash: return MaterialPageRoute(builder: (context) => const SplashScreen()); // 添加你的其他路由 case default: return MaterialPageRoute(builder: (context) => const NotFoundScreen()); } } return MaterialPageRoute(builder: (context) => const NoInternetScreen()); }
4. 实现无网络页面,处理网络恢复跳转
在无网络页面中监听网络状态,恢复时自动跳转回原页面:
class NoInternetScreen extends ConsumerStatefulWidget { const NoInternetScreen({super.key}); @override ConsumerState<NoInternetScreen> createState() => _NoInternetScreenState(); } class _NoInternetScreenState extends ConsumerState<NoInternetScreen> { @override void initState() { super.initState(); // 监听网络状态变化,恢复时返回首页或原页面 ref.listen<ConnectivityResult>(connectivityProvider, (previous, next) { if (next != ConnectivityResult.none) { Navigator.popUntil(context, (route) => route.isFirst); } }); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('无网络连接,请检查网络设置'), ElevatedButton( onPressed: () { // 手动触发网络重新检查 ref.read(connectivityProvider.notifier)._initConnectivity(); }, child: const Text('重试'), ), ], ), ), ); } }
补充说明
- 如果需要验证真实互联网可达性(而非仅连接状态),可以在
_initConnectivity中加入HTTP请求验证(比如请求一个稳定的公共接口),更新状态时结合连接状态和请求结果。 - 确保在项目中已添加
connectivity_plus依赖,并配置好平台权限(比如Android的ACCESS_NETWORK_STATE,iOS的NSAppTransportSecurity)。
内容的提问来源于stack exchange,提问作者Gaurav Khatri
相关产品推荐
相关产品推荐

