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

Riverpod状态未更新:网络连接状态无法正常同步

问题与解决方案

问题现象

使用connectivity_plus结合Riverpod实现网络连接状态管理时,调用update方法传入WiFi/移动网络状态后,监听端始终收到None状态。排查发现ConnectionStatus Provider的build方法会反复执行,将state重置为初始的None()。

相关代码

状态管理Provider

enum InternetConnectionStatus {
  connected,
  disconnected,
}

@riverpod
class ConnectionStatus extends _$ConnectionStatus {
  @override
  Option<InternetConnectionStatus> build() => None();

  void update(List<ConnectivityResult> connectionStatus) {
        debugPrint("new internet connection: $connectionStatus");
        state = connectionStatus.any((status) => [
              ConnectivityResult.mobile.name,
              ConnectivityResult.wifi.name
            ].contains(status.name))
        ? Some(InternetConnectionStatus.connected)
        : Some(InternetConnectionStatus.disconnected);
  }
}

状态更新逻辑

Future<void> _updateConnectionStatus(List<ConnectivityResult> result) async {
    debugPrint("updateConnectionStatus: $result");
    setState(() {
      _connectionStatus = result;
    });
    ref.read(connectionStatusProvider.notifier).update(result);
}

状态监听逻辑

final status = ref.watch(connectionStatusProvider);
debugPrint("internet connection: $status");

实际输出

I  new internet connection: [ConnectivityResult.wifi]
I  internet connection: None

期望输出:传入WiFi/移动网络时,打印internet connection: Some(InternetConnectionStatus.connected)


问题原因

  1. ConnectionStatus的build方法仅返回初始值None(),未处理状态持久化。
  2. 当Provider的监听组件重建时,build方法会重新执行,直接将state重置为None(),覆盖之前通过update设置的状态。
  3. 未利用Riverpod的生命周期自动管理流订阅,手动更新状态的方式无法抵抗Provider的重建行为。

解决方案

方案1:自动订阅连接状态流(推荐)

在build方法中直接订阅connectivity_plus的连接状态流,让Riverpod自动维护状态,无需手动调用update:

enum InternetConnectionStatus {
  connected,
  disconnected,
}

@riverpod
class ConnectionStatus extends _$ConnectionStatus {
  @override
  Future<InternetConnectionStatus> build() async {
    final connectivity = Connectivity();
    // 获取初始连接状态
    final initialResult = await connectivity.checkConnectivity();
    var currentStatus = _mapToCustomStatus(initialResult);

    // 订阅连接状态变化流
    await for (final result in connectivity.onConnectivityChanged) {
      currentStatus = _mapToCustomStatus(result);
      state = AsyncData(currentStatus);
    }

    return currentStatus;
  }

  // 转换ConnectivityResult为自定义状态
  InternetConnectionStatus _mapToCustomStatus(ConnectivityResult result) {
    return [ConnectivityResult.mobile, ConnectivityResult.wifi].contains(result)
        ? InternetConnectionStatus.connected
        : InternetConnectionStatus.disconnected;
  }
}

监听时处理FutureProvider的状态:

final statusAsync = ref.watch(connectionStatusProvider);
statusAsync.when(
  loading: () => debugPrint("正在获取网络状态..."),
  error: (e, st) => debugPrint("获取网络状态失败: $e"),
  data: (status) => debugPrint("internet connection: $status"),
);

方案2:保留手动更新,避免状态重置

如果需要保留手动更新能力,修改build方法确保不会重置已有状态,并初始化初始连接状态:

@riverpod
class ConnectionStatus extends _$ConnectionStatus {
  @override
  Option<InternetConnectionStatus> build() {
    // 初始化时获取初始连接状态
    WidgetsBinding.instance.addPostFrameCallback((_) => _initInitialStatus());
    // 返回当前已有状态,无状态时返回None
    return state ?? None();
  }

  Future<void> _initInitialStatus() async {
    final initialResult = await Connectivity().checkConnectivity();
    update([initialResult]);
  }

  void update(List<ConnectivityResult> connectionStatus) {
    debugPrint("new internet connection: $connectionStatus");
    state = connectionStatus.any((status) => [
          ConnectivityResult.mobile,
          ConnectivityResult.wifi,
        ].contains(status))
        ? Some(InternetConnectionStatus.connected)
        : Some(InternetConnectionStatus.disconnected);
  }
}

监听时正确处理Option类型:

final status = ref.watch(connectionStatusProvider);
status.when(
  (value) => debugPrint("internet connection: $value"),
  none: () => debugPrint("internet connection: None"),
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:02:17