异步Bloc事件处理器中多次emit状态的报错及解决方法
问题解决办法
核心问题是你在事件处理器执行完毕后调用了emit,违反了Bloc的规则——状态只能在事件处理的生命周期内发射。下面是具体的解决方案:
原因分析
当你调用repository.addPhoto时,如果没有等待该异步操作完成就让事件处理器函数返回,后续onSendProgress回调触发的emit就会处于事件处理器已结束的状态,从而抛出异常。
解决方案
方案一:await上传异步操作
确保事件处理器在整个上传过程中保持活跃,直接await addPhoto方法(前提是该方法返回的Future会在上传完成后才完成):
class PhotoBloc extends Bloc<PhotoEvent, PhotoState> { final PhotoRepository repository; PhotoBloc(this.repository) : super(PhotoInitial()) { on<PhotoAdded>((event, emit) async { // 发射初始进度状态 emit(PhotoUploadingState(progress: 0.0)); try { // await 保证事件处理器直到上传完成才结束 await repository.addPhoto( fileBytes: event.fileBytes, onSendProgress: (sent, total) { final progress = (sent / total) * 100; // 此时事件处理器仍在执行,emit合法 emit(PhotoUploadingState(progress: progress)); }, ); // 上传完成后发射成功状态 emit(PhotoUploadSuccess()); } catch (e) { emit(PhotoUploadFailed(error: e.toString())); } }); } }
方案二:将进度回调转为Stream
如果addPhoto的回调逻辑无法通过await覆盖,可以把进度通知转为Stream,在事件处理器中监听流直到上传完成:
改造Repository
class PhotoRepository { final Dio _dio = Dio(); Stream<double> addPhoto(Uint8List fileBytes) { final progressController = StreamController<double>(); _dio.post( '/api/photos', data: fileBytes, options: Options(contentType: 'application/octet-stream'), onSendProgress: (sent, total) { final progress = (sent / total) * 100; progressController.add(progress); if (sent == total) progressController.close(); }, ).catchError(progressController.addError); return progressController.stream; } }
Bloc中监听进度流
class PhotoBloc extends Bloc<PhotoEvent, PhotoState> { final PhotoRepository repository; PhotoBloc(this.repository) : super(PhotoInitial()) { on<PhotoAdded>((event, emit) async { emit(PhotoUploadingState(progress: 0.0)); try { // 监听进度流,直到上传完成 await for (final progress in repository.addPhoto(event.fileBytes)) { emit(PhotoUploadingState(progress: progress)); } emit(PhotoUploadSuccess()); } catch (e) { emit(PhotoUploadFailed(error: e.toString())); } }); } }
说明
以上两种方案都能保证所有emit操作都在事件处理器的执行周期内完成,BlocConsumer可以正常监听状态变化并更新进度条,完全符合你的需求,不需要替换为BlocListener。
内容的提问来源于stack exchange,提问作者xplat
相关产品推荐
相关产品推荐

