【问题标题】:navigator.geolocation.watchPosition return position unavailablenavigator.geolocation.watchPosition 返回位置不可用
【发布时间】:2020-02-02 15:33:39
【问题描述】:

我有一个监控设备位置的服务:

getLocation(opts): Observable<any> {
    return Observable.create(observer => {
        if (window.navigator && window.navigator.geolocation) {
            window.navigator.geolocation.watchPosition((position) => {
                observer.next(position);
            }, (error) => {
                switch (error.code) {
                    case 1:
                        observer.error('errors.location.permissionDenied');
                        break;
                    case 2:
                        observer.error('errors.location.positionUnavailable');
                        break;
                    case 3:
                        observer.error('errors.location.timeout');
                        break;
                }
            }, opts);
        } else {
            observer.error('errors.location.unsupportedBrowser');
        }
    });
}

然后在组件中检索经纬度:

ngOnInit() {
    var source = this.locationService.getLocation({enableHighAccuracy:true, maximumAge:30000, timeout:27000});
    source.subscribe(pos => {
        this.lat = pos.coords.latitude;
        this.long = pos.coords.longitude;
    }, err => {
        this.err = err;
        console.log(err);
    });
}

此代码在 macbook 和 iphone 上的浏览​​器中运行良好,即它可以在设备移动时检索和更新位置。

但在我的 ipad(wifi 只有没有 gps)上,它可以在第一次获得位置,然后几秒钟后,服务返回错误代码 2,即位置不可用并且浏览器停止更新位置。我不确定它是否停止工作或仍在运行但总是返回错误代码2。

我的问题是:

  1. watchPosition 是否需要 GPS 才能工作?但我的macbook 也没有gps。
  2. 如果发生错误并从 observable 返回,我需要重新订阅以再次获取数据(位置)还是等到错误消失。

【问题讨论】:

    标签: angular typescript geolocation rxjs


    【解决方案1】:

    我在某些浏览器中遇到了一个奇怪的错误,它在带有 RxJS、Meteor 和一堆其他东西的 Angular2 服务中使用 navigator.geolocation.watchPosition。不确定原因是什么,但“this”在第一次回调后超出范围,无法在未来的回调中解决。解决方法是创建对当前类的本地范围引用:

    startTracking() {
        let that = this; //The fix            
        let opts = {maximumAge: 60000, timeout: 30000}
        this.watchId = navigator.geolocation.watchPosition((position) =>
            {
                console.log(position);
                that.locationTrackingActive = true;
                that.reactiveDeviceLocation.next(position.coords);
            },
            (err) =>
            {
                console.log(err);
                that.locationTrackingActive = false;
            },
            opts);
    

    }

    发生错误后您无需重新订阅 watchPosition,它会一直尝试直到能够收到信号。对于您的 observable,使用 BehaviorSubject (上面的reactiveDeviceLocation)可以让您设置默认起始位置,然后仅在成功时更新它......这样当新客户端订阅时,他们将获得默认(或最新)位置并且可以可以使用它,直到 watchPosition 成功更新主题。

    我设置如下(在同一个服务中)

    reactiveDeviceLocation: Rx.BehaviorSubject<Object> = new Rx.BehaviorSubject<Object>({latitude:37.5, longitude:122});
    
    getReactiveDeviceLocation() {
        return this.reactiveDeviceLocation;
    }
    

    服务的任何消费者都可以调用

    MyService.getReactiveDeviceLocation.subscribe((pos) => {
       console.log(pos); //Last known location.
    })
    

    【讨论】:

      【解决方案2】:

      这里我使用watchPosition 函数从用户那里获取位置。创建具有默认位置的主题(可选)。当组件加载时,调用getLocation 并在您的组件中,使用异步管道来显示数据。

      Live Demo

      location.component.html

      <div *ngIf="coordindates | async">
        <p>
          {{coordindates | async | json}}
        </p>
      </div>
      

      location.component.ts

      import { Component, OnInit } from '@angular/core';
      import { Router } from '@angular/router';
      import {
          LocationService
      } from '@app/core';
      import { Observable } from 'rxjs';
      
      @Component({
          selector: 'app-location',
          templateUrl: './location.component.html',
          styleUrls: ['./location.component.scss']
      })
      export class LocationComponent implements OnInit {
          coordindates: Observable<Object>;
          constructor(private locationService: LocationService) { }
      
          ngOnInit(): void {
              this.coordindates = this.locationService.getLocation();
          }
      }
      

      location.service.ts

      import { Injectable } from '@angular/core';
      import { BehaviorSubject, Observable, Subject } from 'rxjs';
      @Injectable({
          providedIn: 'root'
      })
      export class LocationService {
          public watchId: number;
          public locationTrackingActive = false;
          public currentLoation: { latitude: number, longitude: number } = { latitude: undefined, longitude: undefined };
          private reactiveDeviceLocation$: Subject<Object>;
      
          constructor() {
              this.reactiveDeviceLocation$ = new BehaviorSubject<Object>(this.currentLoation);
          }
      
          getLocation(): Observable<Object> {
              const opts = { enableHighAccuracy: true, maximumAge: 60000, timeout: 30000 };
              this.watchId = navigator.geolocation.watchPosition((position) => {
                  this.locationTrackingActive = true;
                  this.currentLoation = { latitude: position.coords.latitude, longitude: position.coords.longitude };
                  this.reactiveDeviceLocation$.next(this.currentLoation);
              },
              (err) => {
                  console.log(err);
                  this.locationTrackingActive = false;
              },
              opts);
              return this.reactiveDeviceLocation$;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-05-15
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        • 2019-08-19
        • 1970-01-01
        • 2014-06-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多