Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BLoC does not yield state when requesting for a location in Flutter

Tags:

flutter

dart

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.

  1. Pull to Refresh
  2. BLoC
  3. Geolocator

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.

like image 345
Carrein Avatar asked Dec 14 '22 11:12

Carrein


1 Answers

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 {
}
like image 94
Carrein Avatar answered Dec 16 '22 00:12

Carrein