Flutter Bloc v7.3+ 事件处理新写法与同步异步详解

今天早睡
今天早睡
发布时间:2026-10-16 | 11人浏览过
原创

在 Flutter 开发中,Bloc (Business Logic Component) 是主流的状态管理方案之一。随着 Bloc 库的版本迭代(如 flutter_bloc: ^7.3.1 至 v8.0),官方已标记传统的 mapEventToState 为废弃 API。本文将解析新版 on<Event> 语法的使用方式,重点对比新旧写法在事件执行模式上的差异,并演示如何通过自定义 Transformer 实现事件的同步或异步控制。

老版本标准写法(已废弃)

Bloc 的核心模型包含 State(状态)、Event(事件)和 Bloc 类本身。早期版本通过重写 mapEventToState 方法来响应事件并产出新的 State。

以下是一个自增/自减的简单示例:

/// Event 定义
@immutable
abstract class TestDartEvent {}
class IncreaseEvent extends TestDartEvent {}
class ReduceEvent extends TestDartEvent {}

/// State 定义
class TestDartState {
  int num;
  TestDartState(this.num);
}

/// Bloc 核心逻辑
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
part 'test_dart_event.dart';
part 'test_dart_state.dart';

class TestDartBloc extends Bloc<TestDartEvent, TestDartState> {
  TestDartBloc(TestDartState state) : super(state);

  @override
  Stream<TestDartState> mapEventToState(TestDartEvent event) async* {
    if (event is IncreaseEvent) {
      // 模拟耗时操作
      await Future.delayed(Duration(seconds: 10));
      yield TestDartState(state.num + 1);
    } else if (event is ReduceEvent) {
      yield TestDartState(state.num - 1);
    }
  }
}

在使用界面中,通过 BlocBuilder 监听 State 变化:

class _TestBlocPageState extends State<TestBlocPage> {
  late TestDartBloc _bloc;
  
  @override
  void initState() {
    super.initState();
    _bloc = TestDartBloc(TestDartState(0));
  }

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<TestDartBloc, TestDartState>(
      bloc: _bloc,
      builder: (context, state) {
        return Column(
          children: [
            Text('Current Value: ${state.num}'),
            TextButton(onPressed: () => _bloc.add(IncreaseEvent()), child: Text('Add')),
            TextButton(onPressed: () => _bloc.add(ReduceEvent()), child: Text('Reduce')),
          ],
        );
      },
    );
  }
}

新版本推荐写法:on<Event> 注册监听

在新版本(目标移除 v8.0)中,mapEventToState 已被 on<Event> 取代。该 API 允许开发者在构造函数或独立初始化函数中使用闭包来捕获特定的事件类型,结构更加清晰且符合 Dart 的现代语法习惯。

改造后的 Bloc 代码如下:

class TestDartBloc extends Bloc<TestDartEvent, TestDartState> {
  TestDartBloc(TestDartState state) : super(state) {
    init();
  }

  void init() {
    // 监听 IncreaseEvent
    on<IncreaseEvent>((event, emit) async {
      await Future.delayed(Duration(seconds: 10));
      emit(TestDartState(state.num + 1));
    });

    // 监听 ReduceEvent
    on<ReduceEvent>((event, emit) {
      // 注意:此处直接修改 state 对象并非最佳实践,通常应返回新实例
      emit(TestDartState(state.num - 1));
    });
  }
}

关键区别提示: 新版 emit 需要手动传入新的 State 实例,这强制保证了状态的不可变性(Immutability),避免因直接修改旧对象引发的潜在 Bug。

事件队列的执行机制:阻塞 vs 非阻塞

从传统 async* 切换到 on<Event> 时,最核心的行为变化在于 事件队列的处理策略。

1. 老版本的阻塞特性

在使用 mapEventToState 的 async* 生成器模式下,Bloc 维护一个**串行阻塞队列**。只有当上一个事件的 yield 流程完全结束后,下一个事件才会被入队处理。即使某个事件触发了 10 秒延迟,后续的点击也不会进入处理流程,确保了严格的时序性。

2. 新版本的非阻塞并发特性

使用 on<Event> 进行监听时,默认情况下事件是**异步非阻塞**的。这意味着如果两个相同类型的耗时事件几乎同时触发,它们的回调函数会并行运行,互不干扰。这种设计类似于“事件总线”,在处理短耗时操作或多路信号接收时更为高效。

如何恢复串行阻塞(同步队列)?

如果你希望继续使用 on 的新语法,但要求事件必须按照顺序依次执行(即前一个未完成时,后一个排队等待),可以使用 transformer 参数配合 asyncExpand。

    on<IncreaseEvent>((event, emit) async {
      // 模拟耗时任务
      await Future.delayed(Duration(seconds: 10));
      emit(TestDartState(state.num + 1));
    }, transformer: (events, mapper) => events.asyncExpand(mapper));

其中 asyncExpand 会将流中的每一个事件映射为一个异步流,并串联所有子流。由于它依赖前一个流的完成才能推进,从而实现了与老版本一致的同步串行执行效果。

总结

  • API 迁移:尽快将 mapEventToState 重构为 on<T>,以适应未来 v8.0 版本。
  • 理解语义
    • on<Event> 默认并行异步,适合无状态关联的独立操作。
    • >
    • 搭配 asyncExpand 可降级为串行阻塞,适合必须严格顺序执行的复杂交互。
  • 状态更新:始终使用 emit(NewState) 替换旧的 yield State,确保状态管理的严谨性。

以上就是Flutter Bloc 更新后事件同步与异步详解的详细内容,更多关于Flutter Bloc 进阶使用的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表