bloc icon indicating copy to clipboard operation
bloc copied to clipboard

Question : How to use emit.forEach with multiple streams

Open abuzar-rasool opened this issue 2 years ago • 4 comments

Question

I am trying to use flutter_bloc with multiple streams from my location service and I need to accommodate multiple streams from the service to either emit a state or further get the data from other streams.

Future<void> _onGetLocation(GetLocation event, Emitter<HomeState> emit) async {
    emit.forEach(LocationService.serviceStatusStream, onData(serviceStatus){
         if(serviceStatus==ServiceStatus.enabled){
             // here I want to again access the permission stream
             // if permission stream gives PermissionStatus.granted 
             // then I need to get the Location stream and return the 
             // HomeLocationLoaded() with current position other 
             // Other intermediate states (permission denied, location null
             // will have a separate state emit during the process
         }
         return HomeLocationOff();
     })  
    
  }

Basically, I have three streams connected in the following order ServiceStream -> Permission Stream -> Location Stream. Looking for suggestions to implement it according to the new flutter_bloc 8.x.x recommended way.

I have initially planned to combine the 3 streams into one but that doesn't seem efficient as I will be listening to the permission stream and location stream even if the location service is off. Or I would be listening to the location stream even if the permission status is denied.

abuzar-rasool avatar Jul 11 '22 22:07 abuzar-rasool

Hi, I'm not sure it's a perfect approach, but you can do it like this:

  late final StreamSubscription<ServiceStatus?> _serviceStatusStreamSubscription;
  late final StreamSubscription<PermissionStatus?> _permissionStatusStreamSubscription;

  Future<void> _init(InitEvent event, Emitter<HomeState> emit) async {
    _serviceStatusStreamSubscription = LocationService.listen((serviceStatus) {
      add(ServiceStatusChanged(serviceStatus));
    });

    _permissionStatusStreamSubscription = PermissionService.listen((permissionStatus) {
      ...
    });
  }

  @override
  Future<void> close() {
    _serviceStatusStreamSubscription.cancel();
    _permissionStatusStreamSubscription.cancel();
    return super.close();
  }

alexursul avatar Jul 13 '22 06:07 alexursul

@alexursul Thanks for this! I have already done it using this method for now. However, it doesn't follow the recommended approach for listing to stream in flutter_bloc v8.x.x. I have to keep the code consistent throughout the project. Also, my streams are dependent on the data from the previous stream. In the above case if(serviceStatus==ServiceStatus.enabled) only then I will be listing to permissionStream it. At any point the serviceStatus==ServiceStatus.disabled then I will stop listening to the stream. Btw thanks for taking your time out for this. This surely is a solution, but yes not a perfect one for me I guess!

abuzar-rasool avatar Jul 13 '22 07:07 abuzar-rasool

@felangel do you have any solution in mind for this? Thanks

abuzar-rasool avatar Jul 13 '22 07:07 abuzar-rasool

I'm facing exactly the same issue. Been stuck on it for a while now. Any help @felangel ?

FaazAbidi avatar Jul 13 '22 18:07 FaazAbidi

You could use the event transformer restartable from the bloc_concurreny package. When serviceStatus==ServiceStatus.disabled is true then add an event with a 'stop' flag which handles the permissionStream and return before emit.forEach.

agonhajdari avatar Sep 30 '22 23:09 agonhajdari