Flutter BlocListener executed only once even after event gets re-fired Flutter BlocListener executed only once even after event gets re-fired flutter flutter

Flutter BlocListener executed only once even after event gets re-fired


    else if (event is SettingsUpdateButtonPressedEvent) {      final updateSettingsEither = await updateSettingsCommand(          UpdateSettingsParams(settingsAggregate: event.settings));      yield* updateSettingsEither.fold((failure) async* {        yield SettingsUpdatedFailureState(error: "settingsDatabaseError");      }, (result) async* {        if (result != null) {          //          // this part is the problem.          yield SettingsUpdatedState();        } else {          yield SettingsUpdatedFailureState(              error: "settingsUpdateToDatabaseError");        }      });

In general, you should use Equatable if you want to optimize your code to reduce the number of rebuilds. You should not use Equatable if you want the same state back-to-back to trigger multiple transitions.

The source: when-to-use-equatable

How it works with flutter_bloc is you can't yield the same state. Yes, the above function before yield the state is working fine when you emit the event, but the yield itself doesn't get called.

So basically what happens with your bloc is,

  1. Current state is SettingsFetchedState(settings: result)
  2. You emit SettingsUpdateButtonPressedEvent()
  3. Bloc yield SettingsUpdatedState()
  4. State changes from SettingsFetchedState(settings: result) to SettingsUpdatedState()
  5. Current state is SettingsUpdatedState()
  6. BlocListener listens to state changes from SettingsFetchedState(settings: result) to SettingsUpdatedState()
  7. You emit SettingsUpdateButtonPressedEvent()
  8. Bloc doesn't yield SettingsUpdatedState(), it is ignored because the equality comparison returns true)
  9. BlocListener does nothing because there is no state changes.

How to fix this? I am not confident enough to give suggestion based on my current knowledge, so maybe try what the quote says You should not use Equatable if you want the same state back-to-back to trigger multiple transitions.

EDIT :

LoginBloc works simply because it yield different state for each event. I think you don't notice but it yield LoginLoadingState() before yield either LoginLoggedInState(result) or LoginFailureState(error: "loginUsernamePasswordError")

  1. Current state is LoginInitialState()
  2. Emit event
  3. Yield LoginLoadingState()
  4. State changes from LoginInitialState() to LoginLoadingState()
  5. Yield either LoginLoggedInState() or LoginFailurestate()
  6. State changes from LoginLoadingState() to either LoginLoggedInState() or LoginFailurestate()
  7. Back to step 2 for every event


@Federick Jonathan already given enough explain about the problem but I would like to do addon in this.

First things:It is the standard behaviour of Equatable, Event listeners got called when state changes occurred. If you yield the same state every time then nothing going to happen.

Let's discussed all possible solutions.

  1. Remove Equatable from bloc then every event trigger when state change.

  2. Define start and end state for the state. For example, Create first state as StartDataUpdate and second as EndDataUpdate.

Refer below code

yield StartDataUpdate();//Here... Please specified data changes related to operation.yield EndDataUpdate();
  Stream<ReportsState> setupState({required ReportsState state}) async* {    yield StartReportsState();    yield state;    yield EndReportsState();  }

Using:

 yield* setupState( state: NavigationState() );