Flutter网络状态监听异常:断网弹窗、重连跳转失败及FlutterJNI报错
问题根因
你遇到的报错和跳转失败问题主要由以下5个代码缺陷导致:
- 页面级Connectivity监听没有取消:你在
ForInternetChecking页面的initState中直接监听了网络变化流,但没有持有StreamSubscription实例,也没有在页面销毁时取消监听。页面跳转到SplashScreen后被回收,网络变化回调依然会触发,此时调用已失效的context执行页面操作,就会抛出FlutterJNI was detached的报错。 - 初始状态判断失效:
previous变量没有初始化,默认值为null,首次从无网络恢复时previous == ConnectivityResult.none的判断不成立,跳转逻辑不会执行。 - 弹窗与路由跳转冲突:启动无网络弹出告警弹窗后,路由栈顶层是弹窗路由,直接使用
context执行pushReplacement会作用在弹窗路由上,无法正确跳转到目标页面。 - 重复监听冲突:你同时在
ForInternetChecking页面和全局状态类中监听网络变化,两个回调同时触发会导致重复操作、context异常等问题。 checkinternet方法语法错误:方法末尾throw Exception(e)中的变量e未定义,且未覆盖所有分支的返回值,会触发异步异常。
修复方案
步骤1:修正网络检测页逻辑
class _ForInternetCheckingState extends State<ForInternetChecking> { // 持有监听订阅对象 StreamSubscription? _connectivitySub; // 初始化previous默认值 ConnectivityResult? previous = ConnectivityResult.none; // 记录弹窗是否展示 bool _isDialogShow = false; @override void initState(){ super.initState(); _checkInitialNetwork(); _initConnectivityListener(); } // 初始网络检测逻辑抽离 void _checkInitialNetwork() async { try { final result = await InternetAddress.lookup('google.com'); if(!mounted) return; if(result.isNotEmpty && result[0].rawAddress.isNotEmpty){ _goToSplash(); }else{ _showdialog(); } } on SocketException catch (_){ if(!mounted) return; _showdialog(); } } // 网络监听逻辑抽离 void _initConnectivityListener(){ _connectivitySub = Connectivity().onConnectivityChanged.listen((ConnectivityResult connresult) async { // 页面已销毁直接返回 if(!mounted) return; if(connresult == ConnectivityResult.none){ if(!_isDialogShow) _showdialog(); }else if(previous == ConnectivityResult.none){ // 网络恢复后先校验真实可用性 final hasInternet = await checkinternet(); if(hasInternet && mounted){ _goToSplash(); } } previous = connresult; }); } // 统一跳转逻辑,跳转前先关闭弹窗 void _goToSplash(){ if(_isDialogShow){ Navigator.of(context).pop(); _isDialogShow = false; } Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => SplashScreen())); } void _showdialog(){ _isDialogShow = true; showDialog( context: context, builder: (context) => AlertDialog( title: Text('ERROR'), content: Text("No Internet Detected."), actions: <Widget>[ ElevatedButton( onPressed: () => SystemChannels.platform.invokeMethod('SystemNavigator.pop'), child: Text("Exit"), ), ], ), barrierDismissible: false ); } // 页面销毁时取消监听 @override void dispose() { _connectivitySub?.cancel(); super.dispose(); } // 剩余build逻辑不变 @override Widget build(BuildContext context) { // ...原有代码 } }
步骤2:修正checkinternet方法
Future<bool> checkinternet() async { try { final result = await InternetAddress.lookup('google.com'); return result.isNotEmpty && result[0].rawAddress.isNotEmpty; } on SocketException catch (_) { return false; } catch (_) { return false; } }
步骤3:移除重复监听
全局网络监听只需要放在主页等生命周期长的页面中即可,启动阶段的网络检测只保留ForInternetChecking中的逻辑,避免多个监听回调冲突。
内容的提问来源于stack exchange,提问作者Toujo
相关产品推荐
相关产品推荐

