如何在Flutter应用中实现全局网络连接状态检测?
Flutter全局网络状态监听与离线警告实现方案
问题需求
需要实现以下功能:
- 应用运行期间全局持续监听网络状态变化,直至退出
- 当Wi-Fi和移动网络均关闭时,弹出离线警告弹窗
- 项目基于Provider做状态管理,依赖
internet_connection_checker和connectivity_plus包
现有代码
main.dart
import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:provider/provider.dart'; import 'package:test/page/error.dart'; import 'package:test/routes.dart'; import 'package:test/service/connection_manager.dart'; import 'package:test/service/firebase_service.dart'; import 'package:test/firebase_options.dart'; import 'package:test/globals.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await FirebaseService().initNotifications(); await FirebaseService().initFirebaseRemoteConfig(); int mainCount = 1; try { await deviceManager.getCurrentLocation(); print('Main() is executed for $mainCount time(s)'); mainCount ++; } catch(e) { print('Error getting current location: $e'); try { await deviceManager.getLastestLocation(); } catch (e) { print('Error getting latest location: $e'); } } FlutterError.onError = (FlutterErrorDetails details) { runApp(const MaterialApp( debugShowCheckedModeBanner: false, home: AppErrorScreen(), )); }; runApp( MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => ConnectionManager()), ChangeNotifierProvider(create: (_) => Globals()), ], child: MyApp(), ), ); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: AppRoute().route, localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, debugShowCheckedModeBanner: false, ); } }
connection.dart(ConnectionManager类)
import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; class ConnectionManager with ChangeNotifier { final Connectivity _connectivity = Connectivity(); bool _isConnected = false; late StreamSubscription<List<ConnectivityResult>> _subscription; bool get isConnected => _isConnected; ConnectionManager() { _subscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus); _checkInitialConnection(); } Future<void> _checkInitialConnection() async { final List<ConnectivityResult> connectivityResult = await _connectivity.checkConnectivity(); // await _updateConnectionStatus(connectivityResult); } Future<void> _updateConnectionStatus(List<ConnectivityResult> result) async { bool isConnected = false; if (result != ConnectivityResult.none) { try { final lookupResult = await InternetAddress.lookup('google.com'); isConnected = lookupResult.isNotEmpty; } on SocketException catch (_) { isConnected = false; } } _isConnected = isConnected; notifyListeners(); } }
问题分析
现有代码存在以下问题:
_checkInitialConnection方法中注释了_updateConnectionStatus调用,导致应用启动时无法初始化网络状态- 缺少全局离线警告的触发逻辑,网络断开时不会弹出提示
- 手动实现的网络连通性检测可以用
internet_connection_checker简化 - 未在
ConnectionManager销毁时取消Stream订阅,存在内存泄漏风险
解决方案
1. 完善ConnectionManager类
结合internet_connection_checker优化网络检测逻辑,添加订阅清理:
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:internet_connection_checker/internet_connection_checker.dart'; class ConnectionManager with ChangeNotifier { final Connectivity _connectivity = Connectivity(); final InternetConnectionChecker _connectionChecker = InternetConnectionChecker(); bool _isConnected = false; late StreamSubscription<List<ConnectivityResult>> _connectivitySubscription; late StreamSubscription<bool> _connectionCheckerSubscription; bool get isConnected => _isConnected; ConnectionManager() { // 监听连接类型变化,触发实际网络连通性检测 _connectivitySubscription = _connectivity.onConnectivityChanged.listen((_) { _connectionCheckerSubscription.cancel(); _startConnectionChecker(); }); // 初始化网络检测 _startConnectionChecker(); _checkInitialConnection(); } Future<void> _checkInitialConnection() async { _isConnected = await _connectionChecker.hasConnection; notifyListeners(); } void _startConnectionChecker() { // 监听实际网络连通性状态 _connectionCheckerSubscription = _connectionChecker.onStatusChange.listen((status) { final newStatus = status == InternetConnectionStatus.connected; if (_isConnected != newStatus) { _isConnected = newStatus; notifyListeners(); } }); } @override void dispose() { // 取消订阅,避免内存泄漏 _connectivitySubscription.cancel(); _connectionCheckerSubscription.cancel(); super.dispose(); } }
2. 全局实现离线警告
修改MyApp为StatefulWidget,在根节点监听网络状态变化并触发弹窗:
class MyApp extends StatefulWidget { @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { bool _hasShownOfflineDialog = false; @override Widget build(BuildContext context) { return Consumer<ConnectionManager>( builder: (context, connectionManager, child) { // 网络断开且未弹窗时,触发警告 if (!connectionManager.isConnected && !_hasShownOfflineDialog) { _hasShownOfflineDialog = true; WidgetsBinding.instance.addPostFrameCallback((_) { _showOfflineWarning(context); }); } // 网络恢复时重置弹窗标记 if (connectionManager.isConnected && _hasShownOfflineDialog) { _hasShownOfflineDialog = false; } return MaterialApp.router( routerConfig: AppRoute().route, localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, debugShowCheckedModeBanner: false, ); }, ); } void _showOfflineWarning(BuildContext context) { showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: const Text('网络断开'), content: const Text('Wi-Fi和移动网络均已关闭,请检查网络设置'), actions: [ TextButton( onPressed: () { Navigator.pop(context); _hasShownOfflineDialog = false; }, child: const Text('知道了'), ), ], ), ); } }
3. 依赖配置
确保pubspec.yaml中添加对应依赖:
dependencies: flutter: sdk: flutter provider: ^6.0.5 connectivity_plus: ^4.0.1 internet_connection_checker: ^1.0.0+1
关键说明
connectivity_plus负责检测设备连接类型,internet_connection_checker负责验证实际网络连通性,两者结合避免"假在线"情况- 在
ConnectionManager的dispose方法中取消所有订阅,防止内存泄漏 - 通过
Consumer在根Widget全局监听网络状态,确保任何页面都能触发离线警告 - 用
_hasShownOfflineDialog标记避免重复弹窗,网络恢复后重置标记
内容的提问来源于stack exchange,提问作者Jena.T
相关产品推荐
相关产品推荐

