Home > Mobile >  Flutter bloc bad state of stream
Flutter bloc bad state of stream

Time:10-25

in my class Repository() I have two streamcontrollers running who are listening to changes.

  final remoteStreamController = StreamController<dynamic>.broadcast();
  Stream<dynamic> get remoteId =>
      remoteStreamController.stream.asBroadcastStream();

  final localStreamController = StreamController<dynamic>.broadcast();
  Stream<dynamic> get localJoined =>
      localStreamController.stream.asBroadcastStream();

now when there is an event in my app Im using sink to provide informations threw them, so my bloc.dart where im listening to stream changes can do some work in my app.

class GameBloc extends Bloc<GameBlocEvent, GameBlocState> {
  final Repository repository;
  VideocallBloc(this._agoraRepository) : super(VideocallInitial()) {
...
repository.localJoined.listen((res) {
      repository.lastLocal = res["localJoined"];
      repository.lastRemote = res["remoteId"];
      add(UpdateVideoCall(engine: res["engine"], joined: repository.lastLocal ?? false, remote: repository.lastRemote ?? -1));
    });

    repository.remoteId.listen((res) {
      repository.lastLocal = res["localJoined"];
      repository.lastRemote = res["remoteId"];
      add(UpdateVideoCall(engine: res["engine"], joined: repository.lastLocal ?? false, remote: repository.lastRemote ?? -1));
    });

when the bloc doesn't need the state anymore it calls the close() function, where im closing the streams and some other stuff from my app.

this is the part in my bloc.dart:

@override
  Future<void> close() async {
    //cancel streams
    await _repository.localStreamController.close();
    await _repository.remoteStreamController.close();

    await _repository.engine?.leaveChannel();
    await _repository.engine?.destroy();
    
    await super.close();
  }

If I need it again instead of creating the streams again, it throws me an error:

E/flutter ( 6080): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Bad state: Cannot add new events after calling close

Actually, it wants to call sink in my Repository() again, but it doesn't find my two streams. How can I recall those streams again? I thought it does it automatically.

CodePudding user response:

Consider closing the stream with StreamSubscription instead of closing the repository stream directly as another bloc can be listening to the repository stream and it can cause a problem

class GameBloc extends Bloc<GameBlocEvent, GameBlocState> {
  final Repository repository;
  VideocallBloc(this._agoraRepository) : super(VideocallInitial()) {
localJoinedSubscription = repository.localJoined.listen((res) {
      repository.lastLocal = res["localJoined"];
      repository.lastRemote = res["remoteId"];
      add(UpdateVideoCall(engine: res["engine"], joined: repository.lastLocal ?? false, remote: repository.lastRemote ?? -1));
    });

  remoteIdSubscription = repository.remoteId.listen((res) {
      repository.lastLocal = res["localJoined"];
      repository.lastRemote = res["remoteId"];
      add(UpdateVideoCall(engine: res["engine"], joined: repository.lastLocal ?? false, remote: repository.lastRemote ?? -1));
    });
}

late final StreamSubscription localJoinedSubscription;
late final StreamSubscription remoteIdSubscription;

@override
  Future<void> close() async {
    //cancel streams
    //this just make sures the current bloc closes the stream you are listening to
    localJoinedSubscription.cancel();
    remoteIdSubscription.cancel();

//any other thing you want to close 
    
    await super.close();
  }


}
  • Related