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
相关产品推荐
相关产品推荐

