I have a problem on my flutter app, when try to load a data from api using dio and this api is private so need to be connected to the same network, so to check everything is fine I tried to connect using mobile data that means dio connection won't success and return timeout, when I call that inside BLoC and use BloCBuilder to build UI depending on state bloc return loadingstate then return errorstate and try to do the event again and fail then repeat this over and over, I just want to avoid this and return error state only and stop listening on that event
void _loadAllSpecialities(
LoadAllSpecialities event, Emitter<DoctorsState> emit) async {
emit(
const DoctorsLoadingState(),
);
emit(const DoctorsLoadingState());
final result = await doctorService.getAllSpeciality(event.jwtToken);
print(result.toString());
//has no error and data loaded
if (result.item1 == null) {
final speicailities = result.item2;
emit(DoctorsSpecialitiesLoaded(specialities: speicailities));
} else {
//has error (error not null)
emit(DoctorErrorState(result.item1!));
}
}```
.
class DoctorService {
final List<DoctorSpeciality> specialities = [];
final options = Options(
responseType: ResponseType.json,
receiveTimeout: 2000,
sendTimeout: 2000,
);
final _dio = Dio();
Future<Tuple<String?, List<DoctorSpeciality>>> getAllSpeciality(
String jwtToken) async {
specialities.clear();
var tuple = Tuple<String?, List<DoctorSpeciality>>(null, []);
try {
final response = await _dio.get<List>(ApiVars.specialitiesEndPoint,
options:
options.copyWith(headers: {"Authorization": "Bearer $jwtToken"}));
if (response.statusCode == 200) {
//has no data
if (response.data == null) {
//set error 1
tuple.setNewValues('No data loaded', []);
//print it
log(tuple.item1 ?? '');
//return tuple with error and empty list
return tuple;
}
//has data then map it into list of specialities
response.data?.forEach((element) {
//convert json to speciality and add it to specialities list
specialities.add(DoctorSpeciality.fromJson(element));
});
//set error to null and list to specialites list
tuple.setNewValues(null, specialities);
return tuple;
} else {
//set error to error with the code and list to empty list
tuple.setNewValues('error occur with code ${response.statusCode}', []);
log(tuple.item1 ?? '');
return tuple;
}
} on DioError catch (error) {
//set error to error message and list to empty list
tuple.setNewValues("doc service ${error.message}", []);
log(tuple.item1 ?? '');
return tuple;
}
}
}
I tried add droppable, sequential and didn't work
on<LoadAllSpecialities>(_loadAllSpecialities, transformer: droppable());
I solved the problem by adding Future before function that called inside the handler function and await it to end as code in below ///constructor called super and pass initial state...
on<DoctorsEvent>(
(event, emit) async {
try {
if (event is LoadAllSpecialities) {
// * load all specialities of doctors from api ...
//add await here
await _loadAllSpecialities(event, emit);
}
} catch (error) {
emit(DoctorErrorState(error.toString()));
}
},
);
}
//add future here
Future<void> _loadAllSpecialities(
LoadAllSpecialities event, Emitter<DoctorsState> emit) async {
emit(
const DoctorsLoadingState(),
);
emit(const DoctorsLoadingState());
final result = await doctorService.getAllSpeciality(event.jwtToken);
//has no error and data loaded
if (result.item1 == null) {
final speicailities = result.item2;
emit(DoctorsSpecialitiesLoaded(specialities: speicailities));
} else {
//has error (error not null)
emit(DoctorErrorState(result.item1!));
}
}