You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 02:06:01