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

Flutter Bloc如何通过transformEvents按事件属性排序事件队列

Flutter Bloc 自定义事件排序的实现方案

完全可以通过重写transformEvents结合rxdart、Dart内置优先队列实现,核心要解决的是流式实时调度,而不是等所有事件到齐再做全量排序——这也是很多人一开始实现失败的常见原因。

核心逻辑匹配你的示例需求

结合你给出的输入队列和目标输出队列,逻辑拆解非常明确:

  • 所有带int排序属性的MyEvent不按到达顺序立刻执行,而是先入优先队列,按属性值从小到大排序
  • 遇到不参与排序的AnotherEvent时,先把当前队列里已经攒着的所有MyEvent按升序全部执行完,再执行AnotherEvent
  • 事件流结束时,把队列里剩余的MyEvent按升序依次执行

这套逻辑跑出来的结果和你给出的目标队列完全一致。

完整可运行代码示例

首先定义基础事件类:

abstract class MyBlocEvent {}

class MyEvent extends MyBlocEvent {
  final int sortValue;
  MyEvent(this.sortValue);

  @override
  String toString() => 'MyEvent($sortValue)';
}

class AnotherEvent extends MyBlocEvent {
  @override
  String toString() => 'AnotherEvent()';
}

Bloc类中重写transformEvents实现自定义调度:

import 'dart:collection';
import 'package:bloc/bloc.dart';
import 'package:rxdart/rxdart.dart';

class SortableBloc extends Bloc<MyBlocEvent, int> {
  SortableBloc() : super(0) {
    on<MyEvent>((event, emit) => emit(event.sortValue));
    on<AnotherEvent>((event, emit) => emit(-1));
  }

  @override
  Stream<MyBlocEvent> transformEvents(
    Stream<MyBlocEvent> events,
    Stream<MyBlocEvent> Function(Stream<MyBlocEvent> events) eventMapper,
  ) {
    // 初始化优先队列,规则:sortValue更小的MyEvent排在前面
    final eventQueue = PriorityQueue<MyEvent>(
      (a, b) => a.sortValue.compareTo(b.sortValue),
    );

    return events
        // 逐次处理流入的事件
        .asyncExpand((event) {
          // 遇到非排序类事件时,先排空当前优先队列
          if (event is! MyEvent) {
            final flushedEvents = <MyBlocEvent>[];
            while (eventQueue.isNotEmpty) {
              flushedEvents.add(eventQueue.dequeue());
            }
            flushedEvents.add(event);
            return Stream.fromIterable(flushedEvents);
          }

          // 排序类事件直接入队,不立刻触发执行
          eventQueue.enqueue(event);
          return const Stream.empty();
        })
        // 流结束时,排空队列中剩余的排序事件
        .concatWith([
          DeferredStream(() {
            final remainingEvents = <MyBlocEvent>[];
            while (eventQueue.isNotEmpty) {
              remainingEvents.add(eventQueue.dequeue());
            }
            return Stream.fromIterable(remainingEvents);
          }),
        ])
        .transform(eventMapper);
  }
}

效果验证

当向Bloc依次送入事件[MyEvent(5), MyEvent(3), MyEvent(7), AnotherEvent(), MyEvent(2), MyEvent(1)]时:

  1. 前3个MyEvent依次入队,队列按排序规则存储顺序为[MyEvent(3), MyEvent(5), MyEvent(7)]
  2. 遇到AnotherEvent时,先依次输出队列中的3、5、7三个事件,再输出AnotherEvent
  3. 后续到达的MyEvent(2)、MyEvent(1)依次入队
  4. 事件流结束时,输出队列中剩余的MyEvent(1)、MyEvent(2)

最终实际执行顺序和你给出的目标队列完全一致。

调整说明

  • 如果需求是所有MyEvent永远比AnotherEvent优先级高(不管AnotherEvent什么时候到,都要等所有MyEvent排完再执行),只需要修改优先队列的排序规则,给AnotherEvent分配一个远大于MyEvent的排序值即可
  • Bloc 8.0以下版本的transformEvents参数命名略有差异,核心的流转换逻辑完全通用

内容的提问来源于stack exchange,提问作者Giuseppe Cianci

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 12:54:03