There's three Flutter packages I am using to implement a functionality whereby a user pulls to refresh, a geo-coordinate is retrieved using BLoC logic and passed back to Flutter.
Trouble is, I cannot get the BLoC to yield the return result when I dispatch a call in pull-to-refresh.
geolocation_bloc.dart
class GeolocationBloc extends Bloc<GeolocationEvent, GeolocationState> {
@override
GeolocationState get initialState => GeolocationUninitialized();
@override
Stream<GeolocationState> mapEventToState(GeolocationEvent event) async* {
if (event is RequestLocation) {
yield* _mapGeolocationRequestLocation();
}
}
Stream<GeolocationState> _mapGeolocationRequestLocation() async* {
Position position;
position = await Geolocator().getCurrentPosition();
print("RETRIEVED LOCATION"); // I CAN REACH HERE EVERYTIME.
if (position == null) {
yield LocationLoaded(0, 0);
} else {
yield LocationLoaded(position.latitude, position.longitude);
}
}
Retrieves a geo-coordinate. If sensor is off/broken, return (0,0) instead.
feed_page.dart
@override
void initState() {
super.initState();
_geolocationBloc.dispatch(RequestLocation());
}
void _onRefresh() {
_geolocationBloc.dispatch(RequestLocation());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Username')),
body: BlocProviderTree(
blocProviders: [
BlocProvider<PostBloc>(bloc: _postBloc),
BlocProvider<GeolocationBloc>(bloc: _geolocationBloc),
],
child: BlocListenerTree(
blocListeners: [
BlocListener<GeolocationEvent, GeolocationState>(
bloc: _geolocationBloc,
listener: (BuildContext context, GeolocationState state) {
if (state is LocationLoaded) {
print('LOADED'); // THIS NEVER GETS PRINTED WHEN PULLED TO REFRESH.
lat = state.latitude;
long = state.longitude;
}
..
The driver class dispatches a request RequestLocation()
once in initState()
and every time onRefresh()
is called.
However, while the first time RequestLocation()
is called it is passes successfully i.e. in initState()
, subsequent calls using the pull-to-refresh onRefresh()
method does not seem to yield the LocationLoaded()
state.
log
Restarted application in 2,849ms.
I/flutter ( 6125): AppStarted
I/flutter ( 6125): RequestLocation
I/flutter ( 6125): RETRIEVED LOCATION
I/flutter ( 6125): Transition { currentState: GeolocationUninitialized, event: RequestLocation, nextState: LocationLoaded { latitude: 37.4219983, longitude: -122.084} }
I/flutter ( 6125): LOCATION LOADED
I/flutter ( 6125): RequestLocation
I/flutter ( 6125): RETRIEVED LOCATION
As per the log, the first call prints both RETRIEVED LOCATION and LOCATION LOADED, but nothing else occurs after the second RETRIEVED LOCATION.
How can I fix this such that the pull to refresh will successfully call on the BLoC logic which in turn return a LocationLoaded()
object with the appropriate coordinates.
I managed to solve this by removing the Equatable
inheritance from my State
and Event
BLoC classes. Equatable
implementation of equality checking resulted in the BlocListener not short-circuiting to the corresponding if/else block:
i.e. if (state is LocationLoaded)..
There is a possibility that the equality check is stricter in Equatable
or since I'm passing two coordinates in the state (Latitude/Longitude), it causes the equality check to fail.
State Class:
@immutable
abstract class GeolocationState extends Equatable { // Remove inheritance.
}
class LocationLoaded extends GeolocationState {
}
class GeolocationUninitialized extends GeolocationState {
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With