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

Flutter ObjectBox:getAll()流无响应,如何将流转为列表?

问题描述

我有如下ObjectBox类:

class ObjectBox {
  late final Store _store;
  late final Box<EventData> _eventBox; // EventData是我自定义的模型类

  ObjectBox._init(this._store) {
    _eventBox = Box<EventData>(_store);
  }

  static Future<ObjectBox> init() async {
    final store = await openStore();

    return ObjectBox._init(store);
  }


  Stream<List<EventData>> getEvents() => _eventBox
      .query()
      .watch(triggerImmediately: true)
      .map((query) => query.find());
}

在我的Bloc类中,尝试初始化时加载所有事件:

class ClockBloc extends Bloc<ClockEvent, ClockState> {
  final Stream<List<EventData>> streamEvents;
  ClockBloc({required this.streamEvents}) : super(const ClockState()) {
      on<ClockEvent>(
        _fetchEvents, 
        //transformer: droppable(),
      ); // 这里是我初始化事件的地方
  }
  
  Future<void> _fetchEvents(
      ClockEvent event,
      Emitter<ClockState> emit,
    ) async {
      await emit.onEach(
      streamEvents,
      onData: (data) {
        print('${data.runtimeType} ${data.length}'); // 能打印所有数据,但程序卡在这里出不来
      },
    );
      print('你看不到这行输出'); // 因为一直在等待流结束,永远到不了这里
    }
  }
}

直接把这个流传给StreamBuilder时能正常显示数据。我的问题是:能不能把这个流转换成列表?如果可以,该怎么做?

解决方案

1. 单次获取初始列表

如果你只需要一次性获取当前所有事件的列表,不需要监听后续数据变化,用Stream.first就能拿到流发出的第一个值(因为watch(triggerImmediately: true)会立刻推送当前数据):

Future<void> _fetchEvents(ClockEvent event, Emitter<ClockState> emit) async {
  // 获取流的第一个数据(当前所有EventData的列表)
  final initialEvents = await streamEvents.first;
  print('初始事件数量:${initialEvents.length}');
  // 将列表同步到Bloc状态中
  emit(state.copyWith(events: initialEvents));
  print('这行现在能正常输出');
}

这种方式不会一直等待流结束,first拿到第一个数据后就会完成Future。

2. 同时监听后续更新

如果需要既获取初始列表,又监听后续数据变化,不要用await emit.onEach(它会一直等待流关闭),直接监听流并处理每个数据即可:

class ClockBloc extends Bloc<ClockEvent, ClockState> {
  final Stream<List<EventData>> streamEvents;
  StreamSubscription? _eventsSubscription; // 保存订阅对象,用于后续取消

  ClockBloc({required this.streamEvents}) : super(const ClockState()) {
    on<ClockEvent>(_fetchEvents);
  }
  
  Future<void> _fetchEvents(ClockEvent event, Emitter<ClockState> emit) async {
    // 先取消之前的订阅,避免重复监听
    _eventsSubscription?.cancel();
    // 监听流的所有数据更新
    _eventsSubscription = streamEvents.listen((data) {
      print('事件更新:${data.length}');
      emit(state.copyWith(events: data));
    });
    print('这行能正常输出,同时流会持续监听');
  }

  @override
  Future<void> close() {
    // Bloc关闭时取消订阅,避免内存泄漏
    _eventsSubscription?.cancel();
    return super.close();
  }
}

3. 收集流所有数据为列表(仅适用于有限流)

如果要把流中所有发出的数据收集成一个列表(直到流关闭),可以用Stream.toList(),但注意:ObjectBox的watch流是不会自动关闭的(除非Store关闭),所以这种方式会导致Future永远无法完成,只适合有限长度的流。


内容的提问来源于stack exchange,提问作者Preem Palver2

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 16:45:14