nativescript-geolocation icon indicating copy to clipboard operation
nativescript-geolocation copied to clipboard

How to prevent multiple watchLocation listeners ?

Open Syler921 opened this issue 8 years ago • 5 comments

Hi,

Is there some option to stop all active watchLocation listeners started from the app ?

In my case I have component which starts watchLocation listener every time when is visited. The problem is the previous listeners don't stop to listen for gps location ( and i have multiple active listeners for gps location ).

How can i stop them without to know their watch IDs ?

I tried with simple check :

               if ( !this.watchId ) {
                    this.watchId = geolocation.watchLocation(this.locationReceived, this.error, {
                        desiredAccuracy: 20,
                        updateDistance: 0,
                        minimumUpdateTime: 15000,
                        maximumAge: 6000
                    });
                }

But every time this watchID is different for each new visit in the component and accordingly it`s not created ( this doesn't work ) .

Thanks for help !

Syler921 avatar Jan 02 '17 23:01 Syler921

Hi @Syler921,

It's a very nice idea. We could add something like clearAllWatchIds() similar to the Demo App logic. I've labeled that with the 'good first time' label.

DimitarTachev avatar Oct 12 '17 13:10 DimitarTachev

here:

import {Injectable} from "@angular/core";
import {Observable} from "rxjs/Observable";
import {Subscription} from "rxjs/Subscription";
import {interval} from 'rxjs/observable/interval'
import {timer} from 'rxjs/observable/timer'
import {delayWhen, distinctUntilChanged, flatMap, map, retryWhen, share, switchMap, tap} from 'rxjs/operators'

import {clearWatch, enableLocationRequest, Location as GPSLocation, watchLocation} from "nativescript-geolocation";
import {Accuracy} from "tns-core-modules/ui/enums";
import {Analytics} from "../utils/analytics";

export const DEFAULT_OPTIONS = {
  desiredAccuracy: Accuracy.high,
  minimumUpdateTime: 1000,
  iosAllowsBackgroundLocationUpdates: true
};

export {Location as GPSLocation} from "nativescript-geolocation";

@Injectable()
export class LocationService {

  private _lastLocation: GPSLocation;

  private locationEvents: Observable<GPSLocation>;

  public constructor() {
    this.locationEvents = this.askForLocationPermissions()
      .pipe(
        flatMap(() => new Observable((sub) => {
          let watchId = -1;
          try {
            watchId = watchLocation(
              (loc) => {
                this._lastLocation = loc;
                console.log(`NEW! lat: ${loc.latitude} lon: ${loc.longitude}`)
                sub.next(loc);
              },
              (error) => {
                sub.error(error);
              },
              DEFAULT_OPTIONS);
            console.info(`[watchLocation ${watchId}] Subscribed`);

          } catch(error) {
            sub.error(error);
          }

          return () => {
            if (watchId != -1) {
              console.info(`[watchLocation ${watchId}] Unsubscribed`);
              clearWatch(watchId);
            }
          };
        })),
        switchMap((loc: GPSLocation) => interval(1000)
          .pipe(
            map(() => loc),
            tap((loc) => console.log(`lat: ${loc.latitude} lon: ${loc.longitude}`)))),
        share());
  }

  public get lastLocation(): GPSLocation {
    return this._lastLocation;
  }

  /**
   * Keeps the location updated by calling the given callback, the
   * subscription is returned.
   */
  public keepLocationUpdated(callback: (loc: GPSLocation) => void): Subscription {
      return this.watchLocation()
        .pipe(
          retryWhen((errors) => errors
            .pipe(
              tap((error) => Analytics.logError(error, "Error in keepLocationUpdated, attempting retry in 1 second")),
              delayWhen(() => timer(1000)))),
          distinctUntilChanged((x, y) => x.latitude !== y.latitude || x.longitude !== y.longitude))
        .subscribe(
          (loc) => callback(loc),
          (error) => Analytics.logError(error, "Fatal error in keepLocationUpdated"));
  }

  /**
   * Begins watching the current location.
   */
  public watchLocation(): Observable<GPSLocation> {
    return this.locationEvents;
  }

  /**
   * Asks for location permissions, returns either true or an error.
   */
  public askForLocationPermissions(): Observable<boolean> {
    return new Observable((sub) => {
      enableLocationRequest()
        .then(() => {
          sub.next(true);
          sub.complete();
        })
        .catch(() => sub.error(new Error('Location services not enabled')));
    });
  }

}

briandilley avatar Dec 28 '17 05:12 briandilley

@briandilley how about a vanilla js example

devyaz avatar Sep 22 '18 09:09 devyaz

@devyaz - no

On Sat, Sep 22, 2018, 2:16 AM devyaz [email protected] wrote:

@briandilley https://github.com/briandilley how about a vanilla js example

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/NativeScript/nativescript-geolocation/issues/46#issuecomment-423729747, or mute the thread https://github.com/notifications/unsubscribe-auth/ABBNz4Nun_9ZcB8lz0lMQQJ34ezeACR1ks5udgAHgaJpZM4LZP2f .

briandilley avatar Sep 23 '18 23:09 briandilley

Hey I am quite new to NS and Android and I also need this feature as well. I am thinking of making an improvisation using a for loop. Since the watchID is provided via increment, I am thinking of iterating for all previous values that were used for the watchID and passing them in clearWatch. The problem here is that I need to first get the watchID (which means starting a watchLocation) and afterwards I can clear all previous watchLocation listeners. Is there a way to get the watchID (the current value of watchIdCounter) without starting an watchLocation.

Another option would be to get access to the locationListeners object and remove all existing listeners.

StefanAleksik avatar Dec 25 '19 18:12 StefanAleksik