Flutter Bloc 到 Bloc 通信:如何在初始收听广播流时接收数据?

Flutter Bloc to Bloc Communication: How to receive data on initial listen to broadcast stream?

问题总结: 当我创建一个新的 bloc 时,我正在尝试从 BlocA 的 StateA 获取列表。

简化背景: 我有一个总体集团 (BlocA),它在这个问题的上下文中始终处于活动状态,并且有 2 个屏幕,每个屏幕都有一个相应的集团(BlocB 和 BlocC),当路由到其关联屏幕时创建并在远离其关联屏幕时关闭屏幕。每次创建新区块时,它都需要从 BlocA 的状态中获取数据。用户可能会在屏幕之间来回移动。

我尝试了什么: 我在 BlocA 中创建了流控制器,它通过 getter 将相关数据流式传输到每个块。起初,我尝试了一个正常的(单个监听器)流,最初运行良好。但是,当路由离开然后返回屏幕时,它会在使用 getter 重新订阅同一流时抛出错误。然后我将流控制器实例化为广播流 StreamController.broadcast()。那么问题是,当订阅流时,没有数据像普通流一样在订阅流时传递,当我尝试在广播构造函数中实现 onListen 回调(向接收器添加事件)时,它给出我的错误 The instance member '_aStream' can't be accessed in an initializer。 state 也会出现类似的错误。见下文:

... _aStream = StreamController.broadcast(onListen: () {return _aStream.add(state.TypeX)})

简化的示例代码:

class BlocA extends Bloc<BlocAEvent, BlocAState> {
  BlocA() : super(BlocAState()) {
    on<EventA>(_onevent);
  }

  final StreamController<TypeX> _aStream = StreamController.broadcast();
  Stream<TypeX> get aStream => _aStream.stream;

  final StreamController<TypeY> _bStream = StreamController.broadcast();
  Stream<TypeY> get bStream => _bStream.stream;

  ...
  
  // sink.add()'s are implemented in events
}

class BlocB extends Bloc<BlocBEvent, BlocBState> {
  BlocB({required this.blocA}) : super(BlocBState()) {
    on<EventB>(_onEventB);
    blocASubscription = blocA.aStream.listen((stream) {
      if (stream != state.fieldX) {
        add(EventB(fieldX: stream));
      }
    });
  }

  final BlocA blocA
  late final StreamSubscription blocASubscription;


  FutureOr<void> _onEventB(EventB event, Emitter<BlocBState> emit) {
    emit(state.copyWith(fieldX: event.fieldX));
  }
}
    
class BlocC extends Bloc<BlocCEvent, BlocCState> {
  // similar to BlocB
}

你不需要流,因为 bloc underhood 已经在流中了。您可以通过事件和状态发送任何您想要的东西。查看 Angelov 的图书馆 https://bloclibrary.dev/#/

我最终保留了示例代码中使用的流控制器,但为 BlocA 创建了一个新事件,当用户在屏幕之间切换时触发该事件并将适当的状态数据汇入流中。该事件带有一个索引字段以指示路由到的屏幕。该事件的索引对应于导航栏索引。

事件处理实现如下所示:

  FutureOr<void> _onScreenChanged(
    ScreenChanged event,
    Emitter<BlocAState> emit,
  ) async {
    switch (event.index) {
      case 0:
        _aStream.sink.add(state.fieldX);
        break;
      case 1:
        _bStream.sink.add(state.fieldY);
        break;
      default:
    }
  }