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

Flutter如何等待网络连接状态?启动无网不弹窗及多页面适配疑问

网络连接检测问题排查与全页面适配方案

一、无网启动时弹窗不显示的解决

你的推测正确:Connectivity().onConnectivityChanged流仅在网络状态发生变化时触发回调,应用无网启动时没有状态变更动作,因此不会执行弹窗逻辑。解决思路是在监听流之前,主动检查一次当前网络状态。

修改后的完整代码如下:

class _HomePageState extends State<HomePage> {
  late StreamSubscription subscription;
  bool isDeviceConnected = false;
  bool isAlertSet = false;

  @override
  void initState() {
    super.initState();
    getConnectivity();
  }

  Future<void> getConnectivity() async {
    // 主动检查初始网络状态
    isDeviceConnected = await InternetConnectionChecker().hasConnection;
    if (!isDeviceConnected && !isAlertSet) {
      showDialogBox();
      setState(() => isAlertSet = true);
    }

    // 监听网络状态变化
    subscription = Connectivity().onConnectivityChanged.listen(
      (ConnectivityResult result) async {
        isDeviceConnected = await InternetConnectionChecker().hasConnection;
        if (!isDeviceConnected && !isAlertSet) {
          showDialogBox();
          setState(() => isAlertSet = true);
        } else if (isDeviceConnected && isAlertSet) {
          // 网络恢复时自动关闭弹窗(可选优化)
          Navigator.of(context).pop();
          setState(() => isAlertSet = false);
        }
      },
    );
  }

  @override
  void dispose() {
    subscription.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(/* 页面原有布局 */);
  }

  void showDialogBox() => showDialog(
        context: context,
        barrierDismissible: false,
        builder: (_) => AlertDialog(
          title: const Text("无网络连接"),
          content: const Text("请检查你的网络设置"),
          actions: [
            TextButton(
              onPressed: () async {
                bool hasConnection = await InternetConnectionChecker().hasConnection;
                if (hasConnection) {
                  Navigator.of(context).pop();
                  setState(() => isAlertSet = false);
                }
              },
              child: const Text("重试"),
            )
          ],
        ),
      );
}

核心改动:在getConnectivity方法开头主动调用网络检查接口,直接判断初始状态并触发弹窗逻辑,避免依赖状态变化的流回调。

二、当前实现无法确保所有页面生效

当前代码的网络监听逻辑绑定在HomePage的State中,存在两个致命问题:

  • 当HomePage被弹出栈(比如用Navigator.pushReplacement跳转页面),State会被销毁,监听订阅也会被取消,其他页面无法检测网络状态。
  • 其他页面未嵌入相同监听逻辑,无法触发弹窗提示。

解决方案:全局网络状态管理

将网络检测逻辑抽成全局服务,结合状态管理(如ChangeNotifier+Provider)实现全页面统一监听:

1. 编写全局网络管理类

import 'package:flutter/material.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:internet_connection_checker/internet_connection_checker.dart';

class NetworkManager extends ChangeNotifier {
  late StreamSubscription _connectivitySubscription;
  bool isConnected = false;
  bool isAlertShown = false;

  NetworkManager() {
    _initNetworkListener();
  }

  Future<void> _initNetworkListener() async {
    // 初始网络状态检查
    isConnected = await InternetConnectionChecker().hasConnection;
    notifyListeners();

    // 持续监听网络状态变化
    _connectivitySubscription = Connectivity().onConnectivityChanged.listen(
      (result) async {
        isConnected = await InternetConnectionChecker().hasConnection;
        notifyListeners();
      },
    );
  }

  @override
  void dispose() {
    _connectivitySubscription.cancel();
    super.dispose();
  }
}

2. 在全局注入状态管理

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => NetworkManager(),
      child: const MyApp(),
    ),
  );
}

3. 在MaterialApp的builder中全局处理弹窗

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '网络检测示例',
      home: const HomePage(),
      builder: (context, child) {
        return Consumer<NetworkManager>(
          builder: (context, networkManager, child) {
            // 无网且未弹窗时触发提示
            if (!networkManager.isConnected && !networkManager.isAlertShown) {
              WidgetsBinding.instance.addPostFrameCallback((_) {
                _showNoInternetDialog(context, networkManager);
              });
            }
            // 网络恢复时关闭弹窗
            else if (networkManager.isConnected && networkManager.isAlertShown) {
              Navigator.of(context, rootNavigator: true).pop();
              networkManager.isAlertShown = false;
            }
            return child!;
          },
        );
      },
    );
  }

  void _showNoInternetDialog(BuildContext context, NetworkManager manager) {
    showDialog(
      context: context,
      barrierDismissible: false,
      useRootNavigator: true,
      builder: (_) => AlertDialog(
        title: const Text("无网络连接"),
        content: const Text("请检查你的网络设置"),
        actions: [
          TextButton(
            onPressed: () async {
              bool hasConnection = await InternetConnectionChecker().hasConnection;
              if (hasConnection) {
                Navigator.of(context).pop();
                manager.isAlertShown = false;
              }
            },
            child: const Text("重试"),
          )
        ],
      ),
    );
    manager.isAlertShown = true;
  }
}

该方案优势:

  • 网络监听逻辑全局唯一,避免重复创建订阅浪费资源。
  • 所有页面共享网络状态,弹窗在全局范围内触发,不受页面跳转影响。

内容的提问来源于stack exchange,提问作者krishnaacharyaa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 13:15:06