Flutter如何一次性实现全应用的网络连接状态全局检测
Flutter 全应用统一互联网连通性检测实现方案
多数零散方案无法全局生效的核心原因有两个:一是监听逻辑写在单个页面生命周期里,页面销毁后监听就失效;二是仅依赖系统返回的网络连接标识判断,没有做真实公网连通性校验,会出现假连接误判。
这套方案仅需一次初始化即可覆盖全应用生命周期,自动同步网络状态、全局兜底无网提示,不需要在单个页面重复写检测逻辑。
1. 引入基础依赖
使用两个轻量包完成基础能力支持:
connectivity_plus:监听系统网络类型(WiFi/蜂窝/无连接)的变化internet_connection_checker:发起真实公网请求校验实际连通性,避免假连接误判
在pubspec.yaml中添加依赖:
dependencies: flutter: sdk: flutter connectivity_plus: ^6.0.3 internet_connection_checker: ^1.0.0+1
执行flutter pub get完成安装。
2. 实现全局网络状态单例
单例作为整个应用唯一的网络状态数据源,所有页面、组件、业务逻辑都从这里获取网络状态,避免多监听实例冲突。
// 定义全局网络状态枚举 enum GlobalNetStatus { checking, connected, disconnected } class GlobalNetChecker { // 单例构造 static final GlobalNetChecker _instance = GlobalNetChecker._internal(); factory GlobalNetChecker() => _instance; GlobalNetChecker._internal(); // 广播流供全应用订阅状态变化 final StreamController<GlobalNetStatus> _statusController = StreamController<GlobalNetStatus>.broadcast(); Stream<GlobalNetStatus> get statusStream => _statusController.stream; // 缓存最新网络状态,支持同步获取 GlobalNetStatus currentStatus = GlobalNetStatus.checking; StreamSubscription? _connectivitySub; /// 初始化方法,仅需在应用启动时调用1次 Future<void> init() async { // 启动时先执行一次连通性检测 await _doRealConnectCheck(); // 持续监听系统网络变化,变化时自动重新检测 _connectivitySub = Connectivity().onConnectivityChanged.listen((_) async { _statusController.add(GlobalNetStatus.checking); await _doRealConnectCheck(); }); } // 真实连通性校验逻辑 Future<void> _doRealConnectCheck() async { try { final hasNet = await InternetConnectionChecker().hasConnection; currentStatus = hasNet ? GlobalNetStatus.connected : GlobalNetStatus.disconnected; } catch (_) { currentStatus = GlobalNetStatus.disconnected; } _statusController.add(currentStatus); } /// 供业务层手动触发检测,比如接口请求失败、用户点击重试时调用 Future<void> manualCheck() async { _statusController.add(GlobalNetStatus.checking); await _doRealConnectCheck(); } // 应用退出时释放资源 void dispose() { _connectivitySub?.cancel(); _statusController.close(); } }
3. 配置全局无网兜底提示
通过MaterialApp的builder属性注入全局悬浮提示层,不需要在任何页面单独写判断逻辑,所有页面路由下只要断网就会自动弹出提示:
class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '全局网络检测Demo', theme: ThemeData(primarySwatch: Colors.blue), // 正常配置你的首页、路由表等 home: const HomePage(), // 全局注入网络提示层 builder: (context, child) { return Stack( children: [ child!, Positioned( top: 0, left: 0, right: 0, child: StreamBuilder<GlobalNetStatus>( stream: GlobalNetChecker().statusStream, initialData: GlobalNetChecker().currentStatus, builder: (context, snapshot) { final status = snapshot.data; // 联网/检测中时不显示提示 if (status != GlobalNetStatus.disconnected) { return const SizedBox.shrink(); } // 断网时显示顶部提示条,可根据需求改成弹窗、全屏提示等样式 return Material( child: Container( padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), height: 48 + MediaQuery.of(context).padding.top, color: Colors.redAccent, alignment: Alignment.center, child: const Text( '当前网络不可用,请检查网络连接', style: TextStyle(color: Colors.white, fontSize: 14), ), ), ); }, ), ) ], ); }, ); } }
4. 应用入口初始化
在main函数中启动应用前初始化全局检测单例,一次配置全生命周期生效:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 仅需调用这一次初始化 await GlobalNetChecker().init(); runApp(const MyApp()); }
可选增强能力
- 可以在应用生命周期监听、路由跳转拦截中调用
manualCheck()方法,避免用户切后台修改网络设置后状态不同步 - 可以在网络请求框架(比如Dio)的拦截器中读取
currentStatus,断网时直接拦截请求返回本地错误,减少无效等待 - 可以自定义无网提示样式,比如增加点击重试按钮,触发
manualCheck()重新检测 - 业务页面如果需要根据网络状态做差异化逻辑,直接订阅
statusStream或者读取currentStatus即可,不需要重复注册系统网络监听
内容的提问来源于stack exchange,提问作者Nisha Jain
相关产品推荐
相关产品推荐

