Bloc Listener is not listening to the state changes during multiple emits in same event.
I am performing an async operation to fetch a list of upcoming trips from the repository. Before fetching i am emitting a loading state. After fetching I am emitting a success state along with the list.
Basically there are two emits in same event. BLOC:
Future<void> _onTripsFetchUpcoming(TripsEvent event, Emitter emit) async {
await tripsBlocTryCatchWrapper(() async {
if (event is TripsFetchUpcoming) {
emit(
state.copyWith(
status: TripsStatus.fetchUpcomingTrips,
loadingMessage: "Fetching upcoming trips.",
),
);
final res =
await _tripsRepository.getAllUpcomingTrips(event.opId.toString());
emit(
state.copyWith(
successMessage: "Successfully fetched all upcoming trips.",
status: TripsStatus.fetchedUpcomingTrips,
upcomingTrips: res,
),
);
}
}, emit);
}
I have setup a bloc listener in another widget to listen to these changes and trigger the ModalCubit which shows a modal. For testing I tried with a simple snack bar.
BlocListener<TripsBloc, TripsState>(
listenWhen: (previous, current) =>
previous.status != current.status,
listener: (context, tripsState) {
print(tripsState.status);
if (tripsState.status.isLoading ||
tripsState.status.isFetchingUpcomingTrips) {
context.read<ModalCubit>().showModal(
ModalLoadingChild(
subject: "Trips",
message: tripsState.loadingMessage,
),
"loading",
stopClose: true,
);
} else if (tripsState.status.isFetchedUpcomingTrips ||
tripsState.status.isSuccess) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(tripsState.status.toString())));
print("SUCCESSS");
// context.read<ModalCubit>().hideModal();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(tripsState.status.toString())));
context.read<ModalCubit>().showModal(
ModalSuccessChild(
subject: "Trips",
message: tripsState.successMessage,
),
"success",
);
}
},
);
In the above listener, the loading state emit is being recognized by the listener but it is not picking up the second emit(Success).
Even in ModalCubit Listener only the loading state is shown and not the InActive State.
BlocListener<ModalCubit, ModalState>(
listener: (context, state) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(state.toString())));
},
)
Any emit() after the await _tripsRepository.getAllUpcomingTrips(), is not picked up by the BlocListener
, this is the same case in all my blocs.
Future<void> tripsBlocTryCatchWrapper<T>(
FutureOr<T> Function() tryBlock, void Function(TripsState) emit) async {
try {
await tryBlock();
} on DioError catch (e) {
emit(
TripsError(
message: e.error.toString(),
),
);
} catch (e) {
emit(
TripsError(
message: "Something went wrong in profile.",
),
);
}
}
I would like a solution to implement the bloc listener globally, when I tried with the individual home widget it worked, whereas when I set it as a direct child to MaterialApp, the issue is as described.
When i extracted the listener into a separate widget as used it as a wrapper to every single screen i need, then it will work. It is mostly getting removed from the widget tree somewhere after invocation.