Riverpod StreamProvider异常:AsyncValue始终处于Loading状态求助
问题分析与解决方案
核心问题原因
你的代码主要存在以下几个关键问题:
重复创建
ProtoReceiveMessageChannel实例导致消息处理器被覆盖
StreamProvider的回调会在订阅触发/重新触发时重复执行,每次都会创建新的ProtoReceiveMessageChannel实例。新实例会覆盖同一个channel name的消息处理器,而Widget订阅的是早期实例的流,因此无法收到后续事件。冗余的消息处理器设置
构造函数中已经调用了_binaryMessenger.setMessageHandler,_onListen方法中又重复执行该操作,虽然不会直接报错,但属于无效逻辑。缺少资源清理与异常捕获
没有在实例销毁时关闭StreamController和移除消息处理器,存在内存泄漏风险;同时onMessage方法未捕获解码异常,若解码失败会导致事件丢失且无报错信息。
修复方案
1. 持久化ProtoReceiveMessageChannel实例
通过Provider确保全局只有一个ProtoReceiveMessageChannel实例,避免重复覆盖消息处理器:
final appWindowStateChannelProvider = Provider<ProtoReceiveMessageChannel<AppWindowState>>((ref) { const channelName = 'u/AppWindowState'; final channel = ProtoReceiveMessageChannel<AppWindowState>( channelName, ProtoDecoder<AppWindowState>((bytes) => AppWindowState.fromBuffer(bytes)), ); // 销毁时清理资源 ref.onDispose(() { ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler(channelName, null); channel._streamController.close(); }); return channel; }); final appWindowStateProvider = StreamProvider<AppWindowState>((ref) { final channel = ref.watch(appWindowStateChannelProvider); return channel.messageStream; });
2. 优化ProtoReceiveMessageChannel类
移除冗余逻辑,添加异常捕获:
class ProtoReceiveMessageChannel<T extends GeneratedMessage> { final String name; final BinaryMessenger _binaryMessenger = ServicesBinding.instance.defaultBinaryMessenger; final ProtoDecoder<T> _receiveCodec; late StreamController<T> _streamController; ProtoReceiveMessageChannel(this.name, this._receiveCodec) { _streamController = StreamController<T>.broadcast(); _binaryMessenger.setMessageHandler(name, onMessage); } Stream<T> get messageStream => _streamController.stream; Future<ByteData?>? onMessage(ByteData? message) { try { if (message == null) return null; final decodedMsg = _receiveCodec.decodeMessage(message); if (decodedMsg != null) { _streamController.add(decodedMsg); } } catch (e, stack) { debugPrint('消息解码失败: $e\n$stack'); _streamController.addError(e, stack); } return null; } }
3. 额外验证点
- 确认外部事件发送的channel name与
'u/AppWindowState'完全一致,无拼写错误 - 若流始终无初始事件,可考虑在
ProtoReceiveMessageChannel初始化时主动发送一次初始状态,避免Widget一直处于loading状态
内容的提问来源于stack exchange,提问作者Elad Maimoni
相关产品推荐
相关产品推荐

