Flutter Bloc使用RxDart combineLatest触发Stream已被监听错误
错误原因与修复方案
错误根源
- Dart默认
StreamController创建的是单订阅流,同一时间仅允许存在一个监听器 - 你的代码中
email、pwd两个流会被两处同时监听:一是输入框对应的StreamBuilder做校验提示用,二是CombineLatestStream.combine2组合生成提交校验流时需要分别监听两个流,触发了二次监听的限制,所以抛出异常。此前没有使用combineLatest时每个流仅被输入框的StreamBuilder监听一次,因此运行正常。
修复方案
两种可选方案,推荐使用第二种:
方案1:将普通StreamController改为广播流
修改login_form_bloc.dart中StreamController的初始化逻辑,添加.broadcast构造参数即可:
final _email = StreamController<String>.broadcast(); final _pwd = StreamController<String>.broadcast();
注意:普通广播流不会缓存事件,若流发送事件时没有监听器,事件会丢失,重进页面时也不会保留之前的输入校验状态。
方案2:使用RxDart的Subject替换普通StreamController(推荐)
RxDart的BehaviorSubject、PublishSubject本身就是广播流,其中BehaviorSubject还会缓存最新的一次事件,刚好适配表单场景,页面重构建时也能保留之前的输入和校验状态:
// 先导入rxdart import 'package:rxdart/rxdart.dart'; class LoginFormBloc with Validators { // 替换为BehaviorSubject final _email = BehaviorSubject<String>(); final _pwd = BehaviorSubject<String>(); // 剩余原有逻辑无需修改 Function(String) get changeEmail => _email.sink.add; Function(String) get changePwd => _pwd.sink.add; Stream<String> get email => _email.stream.transform(validateEmail); Stream<String> get pwd => _pwd.stream.transform(validatePwd); Stream<bool> get submitValid => CombineLatestStream.combine2(email, pwd, (a, b) => true); dispose() { _email.close(); _pwd.close(); } }
内容的提问来源于stack exchange,提问作者Divyam Dhadwal
相关产品推荐
相关产品推荐

