Flutter网络状态提示异常:连接无互联网网络时未触发对应SnackBar提示
Flutter网络状态提示异常:连接无互联网网络时未触发对应SnackBar提示
我看了你的代码,发现几个可能导致问题的点,还有可以优化的地方,帮你一步步解决:
问题分析
你遇到的核心问题是:当设备从无网络状态切换到「有网络连接但无互联网」的网络时,对应的SnackBar没有触发,但切换网络或断开网络时正常。可能的原因包括:
- 未检查组件是否已挂载:在流回调的异步操作中,组件可能已经被销毁,导致
ScaffoldMessenger.of(context)无法正常工作 - 并发请求冲突:如果网络状态频繁变化,多个
isInternetAvailable()请求可能同时进行,导致状态混乱 - 初始化状态遗漏:组件启动时如果设备已连接无互联网网络,原代码不会主动检查并触发提示
- 变量名拼写错误:你的代码里
connectivyStream少了一个t(应该是connectivityStream),虽然不影响当前功能,但容易引发后续维护问题
修复后的完整代码
import 'package:flutter/material.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:dio/dio.dart'; import 'package:google_fonts/google_fonts.dart'; class NetworkStatusScreen extends StatefulWidget { const NetworkStatusScreen({super.key}); @override State<NetworkStatusScreen> createState() => _NetworkStatusScreenState(); } class _NetworkStatusScreenState extends State<NetworkStatusScreen> { final Connectivity _connectivity = Connectivity(); bool _isConnectedToInternet = false; late final StreamSubscription _connectivityStream; final Dio _dio = Dio(); bool _isCheckingInternet = false; // 防止并发检查互联网状态 Future<bool> _isInternetAvailable() async { if (_isCheckingInternet) return false; // 避免同时发起多个检查请求 _isCheckingInternet = true; try { final response = await _dio.get( 'https://www.google.com', options: Options( receiveTimeout: const Duration(seconds: 3), sendTimeout: const Duration(seconds: 3), ), ); return response.statusCode == 200; } on DioException catch (e) { // 分类处理Dio错误 switch (e.type) { case DioExceptionType.connectionTimeout: print("连接超时,可能无互联网。"); case DioExceptionType.receiveTimeout: print("接收超时,互联网可能很慢。"); case DioExceptionType.badCertificate: print("SSL证书验证失败。"); case DioExceptionType.connectionError: print("无互联网或DNS解析失败。"); default: print("其他Dio错误: ${e.message}"); } return false; } catch (e) { print("未知错误: $e"); return false; } finally { _isCheckingInternet = false; // 重置检查状态 } } @override void initState() { super.initState(); // 初始化时先检查当前网络状态(解决启动时已连接无互联网网络的情况) _checkInitialNetworkStatus(); // 监听网络状态变化流 _connectivityStream = _connectivity.onConnectivityChanged.listen( (List<ConnectivityResult> results) async { if (!mounted) return; // 组件已销毁,直接终止逻辑 bool hasNetworkConnection = !results.contains(ConnectivityResult.none); if (hasNetworkConnection) { bool hasInternet = await _isInternetAvailable(); setState(() { _isConnectedToInternet = hasInternet; }); // 确保组件未销毁再显示提示 if (mounted) { _showStatusSnackBar( hasInternet ? '已连接到互联网!' : '已连接到网络,但无互联网访问!' ); } } else { setState(() { _isConnectedToInternet = false; }); if (mounted) { _showStatusSnackBar('未连接到任何网络!'); } } }, ); } // 初始化时检查当前网络状态 Future<void> _checkInitialNetworkStatus() async { final results = await _connectivity.checkConnectivity(); bool hasNetworkConnection = !results.contains(ConnectivityResult.none); if (hasNetworkConnection) { bool hasInternet = await _isInternetAvailable(); setState(() { _isConnectedToInternet = hasInternet; }); if (mounted && !hasInternet) { _showStatusSnackBar('已连接到网络,但无互联网访问!'); } } } // 封装SnackBar显示逻辑,减少重复代码 void _showStatusSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( message, style: GoogleFonts.poppins(fontWeight: FontWeight.bold), ), duration: const Duration(seconds: 3), backgroundColor: message.contains('无互联网') ? Colors.orange : message.contains('未连接') ? Colors.red : Colors.green, ), ); } @override void dispose() { _connectivityStream.cancel(); // 取消流订阅,防止内存泄漏 super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('网络状态监测')), body: Center( child: Text( _isConnectedToInternet ? '当前已连接互联网' : '当前无互联网访问', style: const TextStyle(fontSize: 20), ), ), ); } }
关键优化点说明
- 添加组件挂载检查:在所有异步操作后都先判断
mounted,避免组件销毁后调用ScaffoldMessenger或setState导致的错误(这是你遇到无提示的核心原因之一) - 防止并发请求:新增
_isCheckingInternet变量,避免同一时间发起多个互联网可用性检查请求,防止状态混乱 - 初始化状态检查:新增
_checkInitialNetworkStatus方法,解决组件启动时设备已连接无互联网网络的情况,确保此时也能触发提示 - 优化视觉区分:给不同状态的SnackBar设置不同背景色,让用户更直观区分网络状态
- 代码封装:把SnackBar显示逻辑抽成单独方法,减少重复代码,提高可维护性
- 修正变量名:把拼写错误的
connectivyStream改为_connectivityStream,避免后续维护混淆
额外建议
- 可以把
_isInternetAvailable()中的请求地址换成你自己的后端接口,比请求Google更稳定(如果你的应用有自有服务器的话) - 根据你的用户场景,3秒的超时时间可以适当调整,比如缩短到2秒提升响应速度
- 可以给SnackBar添加关闭按钮,让用户手动关闭提示
内容来源于stack exchange
相关产品推荐
相关产品推荐

