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)
问题原因
ConnectionStatus的build方法仅返回初始值None(),未处理状态持久化。- 当Provider的监听组件重建时,
build方法会重新执行,直接将state重置为None(),覆盖之前通过update设置的状态。 - 未利用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
相关产品推荐
相关产品推荐

