Flutter中如何暂停Bloc运行、中断Bloc内部的for循环?
问题根因
Bloc 默认采用顺序事件处理策略:前一个事件的处理逻辑完全执行完毕前,后续进入队列的事件会一直等待调度。你当前的 Start 事件中包含了总耗时10秒的for循环,循环执行期间 Stop 事件无法被调度处理,_isRunning 自然不会被修改,只有循环结束后 Stop 事件才会被执行,达不到中途终止循环的效果。
解决方案
方案1:使用并发事件转换器(适配Bloc 7.2+ 版本,推荐)
Bloc 官方提供的 bloc_concurrency 包支持自定义事件并发策略,使用 concurrent 转换器即可允许多个事件并行处理,收到 Stop 事件时会立即执行修改 _isRunning 的逻辑,中断循环:
import 'package:bloc/bloc.dart'; import 'package:bloc_concurrency/bloc_concurrency.dart'; // 省略自定义Event和State的定义 class MyBloc extends Bloc<MyEvent, MyState> { MyBloc() : super(Stopped()) { on<MyEvent>( (event, emit) async { if (event is Start) { _isRunning = true; emit(Running()); for (var i = 0; i < 10; i++) { if (!_isRunning) break; print('$i'); await Future.delayed(const Duration(seconds: 1)); } if (_isRunning) { emit(Stopped()); } } if (event is Stop) { _isRunning = false; emit(Stopped()); } }, // 关键配置:允许事件并发处理 transformer: concurrent(), ); } bool _isRunning = false; }
方案2:使用可取消异步任务(兼容旧版Bloc)
如果使用的是不支持事件转换器的旧版Bloc,可以借助 async 包的 CancelableOperation 封装循环逻辑,收到 Stop 事件时直接取消异步任务终止循环:
import 'package:bloc/bloc.dart'; import 'package:async/async.dart'; // 省略自定义Event和State的定义 class MyBloc extends Bloc<MyEvent, MyState> { MyBloc() : super(Stopped()); bool _isRunning = false; CancelableOperation? _loopTask; @override Stream<MyState> mapEventToState(MyEvent event) async* { if (event is Start) { _isRunning = true; yield Running(); _loopTask = CancelableOperation.fromFuture(() async { for (var i = 0; i < 10; i++) { if (!_isRunning) break; print('$i'); await Future.delayed(const Duration(seconds: 1)); } }()); await _loopTask?.valueOrCancellation(); if (_isRunning) { yield Stopped(); } } if (event is Stop) { _isRunning = false; await _loopTask?.cancel(); yield Stopped(); } } }
注意事项
- 两种方案都添加了状态重复发射校验,避免
Stop事件已经抛出Stopped状态后,循环结束再次抛出相同状态 - 循环逻辑中如果有资源占用,建议在取消任务时添加资源释放逻辑
内容的提问来源于stack exchange,提问作者Vipul Tyagi
相关产品推荐
相关产品推荐

