I have the following problem...
emit was called after an event handler completed normally. This is usually due to an unawaited future in an event handler. Please make sure to await all asynchronous operations with event handlers and use emit.isDone after asynchronous operations before calling emit() to ensure the event handler has not completed.
BAD on((event, emit) { future.whenComplete(() => emit(...)); });
GOOD on((event, emit) async { await future.whenComplete(() => emit(...)); }); )
What happens is that in a function called _onLogIn, if the user has changed the language, it goes from there to another function inside the bloc, these two functions do not depend on each other, I mean that each function is called in different pages of the application, but still _onLogIn checks the _onChangeLanguage function.
UserBloc({this.usecases}) : super(UserInitial()) {
on<LogInEvent>(_onLogIn);
on<ChangeLanguageEvent>(_onChangeLanguage);
}
_onLogIn function :
void _onLogIn(
LogInEvent event,
Emitter<StateA> emit,
) async {
emit(UserLoading());
final userOrFailure = await services.logIn(
x: event.x,
y: event.y,
);
await userOrFailure.fold((user) async {
/// If the user is logging in for the first time and does not
/// have a preferred language.
if (user.preferredLanguage == null) {
emit(UserSuccess());
emit(UserAlreadyLogged(connectedUser));
} else {
/// An ChangeLanguageEvent object
ChangeLanguageEvent event = ChangeLanguageEvent(
user.preferredLanguage,
user.someId,
);
/// Call the other function in the same bloc
this._onChangeLanguage(
event,
emit,
isFromLogin: true,
);
}
}, (failure) {
emit(UserError(failure.message));
});
}
_onChangeLanguage function :
void _onChangeLanguage(
ChangeLanguageEvent event,
Emitter<StateA> emit, {
bool isFromLogin = false,
}) async {
final successOrFailure = await services.updateLanguage(
event.language,
event.someId,
);
await successOrFailure.fold( // ! HERE THE ERROR WHEN I LOG IN; but when i changed the language from the application i don't have an error
(language) async {
emit(ChangeAppLanguage(language));
final sessionOrFailure = await services.getSession();
sessionOrFailure.fold(
(session) {
/// I need this condition to know if the language comes from login
if (isFromLogin) {
emit(UserSuccess());
}
emit(UserAlreadyLogged(session));
},
(failure) => emit(UserError(failure.message)),
);
},
(failure) {
emit(UserError(failure.message));
},
);
}
Any idea why? Thank you
void _onChangeLanguage(
ChangeLanguageEvent event,
Emitter<StateA> emit, {
bool isFromLogin = false,
}) async
This should be a major red flag. A call marked as async
, but not returning a Future<>
. There is no way, the caller could possibly await this call. Or even know that they should await this call.
Make it return a proper Future<void>
instead of just void
and your bloc should pick up on that and properly await the call.
There even is a linter rule for this: avoid_void_async. Did you turn off your linter? Don't do that. Turn your linter on and listen to it. Your other function has the same problem.