mcharmas / Android-ReactiveLocation

Small library that wraps Google Play Service API in brilliant RxJava Observables reducing boilerplate to minimum.
2.11k stars 312 forks source link

Duplicate location updates when I use multiple objects of ReactiveLocationProvider #190

Open debugger22 opened 6 years ago

debugger22 commented 6 years ago

First of all thanks for the awesome work on this library!

I recently ran into a strange issue. I am using two objects of ReactiveLocationProvider namely mReactiveLocationProviderActive and mReactiveLocationProviderPassive. The active one sends location updates only when the device moves a specified distance with an interval of 5 seconds whereas the passive one sends location updates every minute with no restriction on the displacement.

It works in most cases except in some cases where it starts sending duplicate lat/lng. For example, look at the following table. The lat/lng pairs are same where as the accuracy is different.

Time Latitude Longitude Accuracy
04 Jul 2018 06:24:33 PM IST 19.11526 72.85758 15.151
04 Jul 2018 06:15:58 PM IST 19.11526 72.85758 15.062
04 Jul 2018 06:13:11 PM IST 19.11526 72.85758 15.1
04 Jul 2018 06:12:26 PM IST 19.11526 72.85758 15.089
04 Jul 2018 06:11:00 PM IST 19.11526 72.85758 15.222
04 Jul 2018 06:02:30 PM IST 19.11526 72.85758 20.09
04 Jul 2018 05:46:29 PM IST 19.11526 72.85758 24.2

It works perfectly fine when there is only a single object of ReactiveLocationProvider.

Following is the code which I am using.


@Inject
ReactiveLocationProvider mReactiveLocationProviderActive;
@Inject
ReactiveLocationProvider mReactiveLocationProviderPassive;

private LocationRequest       mLocationRequestActive;
private LocationRequest       mLocationRequestPassive;

/**
 * Actively gets location update only when vehicle moves with a fixed time period
 */
private void requestLocationUpdatesActive() {
    mLocationRequestActive = LocationRequest.create();
    mLocationRequestActive.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequestActive.setFastestInterval(5000);
    mLocationRequestActive.setInterval(5*1000);
    mLocationRequestActive.setSmallestDisplacement(5.0f);

    mSubscriptions.add(mReactiveLocationProviderActive
                               .getUpdatedLocation(mLocationRequestActive)
                               .observeOn(AndroidSchedulers.mainThread())
                               .subscribe(this::onLocationChanged,
                                          throwable -> Timber.e(throwable,
                                                                "Location request error")));
}

/**
 * Passively gets location update irrespective of whether vehicle is moving or not
 */
private void requestLocationUpdatesPassive() {
    mLocationRequestPassive = LocationRequest.create();
    mLocationRequestPassive.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequestPassive.setFastestInterval(60000);
    mLocationRequestPassive.setInterval(60*1000);

    mSubscriptions.add(mReactiveLocationProviderPassive
                               .getUpdatedLocation(mLocationRequestPassive)
                               .observeOn(AndroidSchedulers.mainThread())
                               .subscribe(this::onLocationChanged,
                                          throwable -> Timber.w(throwable,
                                                                "Location request error")));
}

/**
* Sends location update to the server
*/
private void onLocationChanged(Location newLocation) {
  // Send location update to the server
}

Library versions that I am using:

Any help would be highly appreciated. TIA.

debugger22 commented 6 years ago

@mcharmas Hey could you please take a look at this issue.

mcharmas commented 6 years ago

Hi @debugger22, to be honest I have no idea what can be the case here. Library is just a wrapper on play services and no state is shared between multiple instances of ReactiveLocationProvider object.

It should not even matter if you are using multiple instances of ReactiveLocationProvider vs one instance. For each locations subscription there is new connection to play services being made and data you get comes straight from location services.

If you want to get rid of duplicates you can merge these two observables and use distinct() operator on the observable but be aware of memory implications. Maybe distinctUntilChanged() will better for your use case? Having one subscription would be more elegant solution especially if you don't need a distinction where location is coming from.