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

Flutter网络状态提示异常:连接无互联网网络时未触发对应SnackBar提示

Flutter网络状态提示异常:连接无互联网网络时未触发对应SnackBar提示

我看了你的代码,发现几个可能导致问题的点,还有可以优化的地方,帮你一步步解决:

问题分析

你遇到的核心问题是:当设备从无网络状态切换到「有网络连接但无互联网」的网络时,对应的SnackBar没有触发,但切换网络或断开网络时正常。可能的原因包括:

  1. 未检查组件是否已挂载:在流回调的异步操作中,组件可能已经被销毁,导致ScaffoldMessenger.of(context)无法正常工作
  2. 并发请求冲突:如果网络状态频繁变化,多个isInternetAvailable()请求可能同时进行,导致状态混乱
  3. 初始化状态遗漏:组件启动时如果设备已连接无互联网网络,原代码不会主动检查并触发提示
  4. 变量名拼写错误:你的代码里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),
        ),
      ),
    );
  }
}

关键优化点说明

  1. 添加组件挂载检查:在所有异步操作后都先判断mounted,避免组件销毁后调用ScaffoldMessenger或setState导致的错误(这是你遇到无提示的核心原因之一)
  2. 防止并发请求:新增_isCheckingInternet变量,避免同一时间发起多个互联网可用性检查请求,防止状态混乱
  3. 初始化状态检查:新增_checkInitialNetworkStatus方法,解决组件启动时设备已连接无互联网网络的情况,确保此时也能触发提示
  4. 优化视觉区分:给不同状态的SnackBar设置不同背景色,让用户更直观区分网络状态
  5. 代码封装:把SnackBar显示逻辑抽成单独方法,减少重复代码,提高可维护性
  6. 修正变量名:把拼写错误的connectivyStream改为_connectivityStream,避免后续维护混淆

额外建议

  • 可以把_isInternetAvailable()中的请求地址换成你自己的后端接口,比请求Google更稳定(如果你的应用有自有服务器的话)
  • 根据你的用户场景,3秒的超时时间可以适当调整,比如缩短到2秒提升响应速度
  • 可以给SnackBar添加关闭按钮,让用户手动关闭提示

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 10:08:00