You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 11:03:03