GPS详解

GPS本身并不复杂,但是因为GPS本身定位比网络还慢的原因用好GPS还是需要费点事的。

  • GPS详解

    • 1. GPS相关类说明(android.location包)

      • 1.1. 主要必须涉及到的类
      • 1.2. API 23及以下版本
      • 1.3. API 24及以上版本
      • 1.4. 不需要用到的类
    • 2. GPS相关基础知识说明
    • 3. GPS定位相关方法(以API 23及以下版本为例)
      • 3.1. Provider相关方法
      • 3.2. 请求定位相关方法(只看方法名,忽略具体参数)
      • 3.3. 添加GPS状态监听
    • 4. GPS定位步骤
      • 4.1. Android中 GPS定位极为简单,首先拿到LocationManager对象:
      • 4.2. 创建定位成功的监听器
      • 4.3. 将定位监听器注册到LocationManager上去
    • 5. 卫星状态监听,并根据卫星状态判断是否继续定位
      • 5.1. 创建卫星状态监听器
      • 5.2. 监听卫星状态
      • 5.3. 基于卫星状态的定位实现
    • 6. GPS定位方案改进版
    • 7. Blog 说明

1. GPS相关类说明(android.location包)

1.1. 主要必须涉及到的类

  • LocationManager 用于发起定位请求
  • LocationListener 用于监听定位信息的有关更新(包括位置变化、相关定位设备状态改变或用户打开关闭相关定位设备)
  • Location 定位信息
  • Criteria 帮助开发者选取最好用的定位设备

采用GPS定位时往往需要监听卫星状态,根据卫星状态去决定是否继续采用GPS定位还是采用其他替补定位方式。在android的location包中同样提供了相关功能,但是在API 24以上定位相关包结构有所更改。

1.2. API 23及以下版本

  • GpsStatus 所有搜索到的卫星状态信息,其中有一个GpsStatus.Listener用于监听卫星状态的改变。
  • GpsSatellite 单个的卫星信息,包括卫星的方位、高度、伪随机噪声码、信噪比等信息,具体的可进入源码查看。

1.3. API 24及以上版本

  • GnssStatus 相当于将GpsStatus以及GpsSatellite整合在了一起

API 24只是对定位接口进行了一些接口上的改进,除了使用起来更加方便以外没有什么其他优势。

1.4. 不需要用到的类

  • Address、Geocoder、GnssClock、GnssMeasurement、GnssMeasurementsEvent、GnssNavigationMessage、SettingInjectorService、LocationProvider这些class 用于通过经纬度获取地理信息以及自定义一些定位实现等,只有定位需求的问题并不需要这些。

2. GPS相关基础知识说明

需要了解,在设置界面或者下拉菜单中的GPS按钮,仅仅是一个GPS的总开关而已,打开它GPS并不会开始定位,只是打开了GPS的访问权限,使具有权限的APP可以去请求GPS进行定位,真正GPS开始工作以及停止工作需要应用程序去控制。

国测局坐标(火星坐标,GCJ02)。国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密,而在国内正常销售、使用的GPS芯片获取的定位信息也必须通过GCJ-02进行处理,处理成加密后的坐标。这将导致国外未采用GCJ02坐标系统的地图在采用了GCJ坐标系统的GPS上不能正常使用,反之亦然。

LocationManager中包含有几种定位模式,NETWORK_PROVIDER、GPS_PROVIDER、PASSIVE_PROVIDER这几种(API 28中又提供了一种WIFI模式),但在当前常见手机中可用的只有两个GPS_PROVIDER已经PASSIVE_PROVIDER。需要注意的是带GPS的Android设备一般肯定支持GPS,但是可以访问网络的手机却并不一定提供NETWORK_PROVIDER的支持(虽然系统可能不支持网络定位,但我们的程序却可以自己去实现基站定位)。

不要相信国内系统的LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))的返回值,国内被改过的系统中isProviderEnabled用于判断GPS还是可以的,判断其他定位方式就算了。

  • 一篇关于GPS定位写得最详实清晰的文章之一
  • GPS的一些浅显知识兼介绍一下GPS测试仪

3. GPS定位相关方法(以API 23及以下版本为例)

Android GPS定位主要通过LocationManager类来实现,其中提供了很多方法,大体上可以分为这么几类方法:

3.1. Provider相关方法

  • createProvider
  • getAllProviders
  • getProviders
  • getProvider
  • getBestProvider

这几个方法用于获取位置提供商,但是在国内没有实际用处,只需要GPS即可。

3.2. 请求定位相关方法(只看方法名,忽略具体参数)

  • requestLocationUpdates (开始GPS定位,GPS开始工作)
  • requestSingleUpdate (开始GPS定位,GPS开始工作)
  • removeUpdates (停止GPS定位,GPS有可能会停止工作,因为有可能其他的APP也启用了GPS)

这几个方法开始请求GPS定位,用于获取位置信息。

3.3. 添加GPS状态监听

  • addGpsStatusListener
  • removeGpsStatusListener

GPS定位过程中,卫星会处于不断变化中,这几个方法可以注册卫星状态监听器用于实时监测卫星状态的变化。

4. GPS定位步骤

4.1. Android中 GPS定位极为简单,首先拿到LocationManager对象:

LocationManager mLocationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);

4.2. 创建定位成功的监听器

LocationListner listener = new LocationListener() {@Overridepublic void onLocationChanged(Location location) {// 收到位置信息(onLocationChanged 不要纠结于方法名,下面会明白)}@Overridepublic void onStatusChanged(String provider, int status, Bundle extras) {// 定位提供程序状态发生改变(国内只考虑GPS,而GPS一般不会回调这个方法)}@Overridepublic void onProviderEnabled(String provider) {// GPS打开}@Overridepublic void onProviderDisabled(String provider) {// GPS 关闭}};

4.3. 将定位监听器注册到LocationManager上去

上面提到 请求定位相关方法,这些以request开头的方法,可以将我们写好的定位监听注册到系统的定位进程上(其实是注册在了你的LocationManager对象上,而LocationManager对象中一个内部类对象注册在系统进程上,IPC相关),系统定位进程收到定位请求开始根据具体参数执行定位请求,当系统进程成功获取到定位信息后回去遍历通知所有注册过来的位置监听器(LocationListener)。当然,如果你的设备只支持GPS,你定位请求使用NETWORK_PROVIDER正常情况下是不会通知你的位置监听器的。具体看下request相关方法:

如在 请求定位相关方法 中看到的,定位相关方法主要有两类,分别是requestLocationUpdates、requestSingleUpdate。其中requestLocationUpdates方法用于表达不断地获取位置信息,具体的看其中一个

public void requestLocationUpdates(String provider, long minTime, float minDistance,LocationListener listener)

该方法第一个参数表示定位设备类型(国内手机直接使用GPS_PROVIDER),第二个表示多长时间才回调一次LocationListener,第三个参数表示距离上一次定位位置超过多远才回调一次LocationListener。

需要注意的是,上面的方法看似很完美,其实却存在很大缺陷,原因有三:

  • GPS定位是一个缓慢的过程。GPS冷启动一般需要40s左右才能收到定位回调,热启动定位还算较快一般数秒内可以定位成功。
  • 而且在室内没有GPS信号,意味着在室内是不可能通过GPS定位成功的
  • 即使是在室外,也受到你所处的环境的限制,空旷的地方定位速度比高楼林立的地方要准确很多快很多。

而你注册的LocationListener只有等到你定位成功的时候他的onLocationChange(Location )方法才会被回调。也就是说,很多时候,你在requestLocationUpdates中设置了minTime、minDistance会发现实际效果并不好,这个时候不要奇怪很正常。

你会发现,在重载的几个requestLocationUpdates方法中,有时候会有一个Criteria或者Looper对象,这两个对象都是给开发者提供一些便利的工具。

  • 其中Criteria对象是帮助你在不同Android设备上选择不同的定位设备,通过Criteria中参数的配置,会选择一个最适合的定位设备进行定位。但是在国内就没必要了,直接用GPS就行,你没有其他选择。
  • Looper对象是帮助你在你指定的线程中回调你注册的LocationListener对象中的各个方法。

request相关方法中还有一类requestSingleUpdate,该类requestSingle方法表示进行单次定位,即定位成功以后便会自动解绑掉注册在系统进程的LocationManager。

需要注意的是,不管是上面requestLocationUpdates方法或者是requestSingleUpdate方法,从该方法被调用开始直至成功获取到定位信息,这段时间内GPS芯片将处于活跃状态,而活跃的GPS芯片会影响到系统休眠,导致系统不能进入休眠状态,造成耗电。具体点说,调用requestLocationUpdates将导致GPS一直处于活跃状态,而调用requestSingleUpdate方法会导致第一次回调onLocationChange之前GPS芯片一直处于活跃状态。所以,在某些状况下设备必须具备主动停掉GPS的机制,当然这种机制要使用LocationManager的removeUpdates去实现。

5. 卫星状态监听,并根据卫星状态判断是否继续定位

上面提到,为了节省Android设备的电量,启动GPS定位后某些情况下必须要关掉GPS。如果GPS正常定位,数秒内定位成功,这种情况下很好处理,我们采用requestSingleUpdate方法实现单次定位即可,但是如果处于室内,没有GPS信号的情况下我们将长时间处于定位状态,电池电量将很快耗尽。而对于requestLocationUpdates方法更是需要在某种情况下去停掉GPS。

我们最重要的任务就是要找到关掉GPS的时机。基于上面分析可以找到这个时机,就是,当我们确定GPS在这种情况下永远都不能成功定位时,就需要关闭掉GPS。但是怎么确认GPS永远也定不到位呢?这就需要去通过GPS芯片收到的GPS卫星信号去做出判断。于是就引出了我们对于GPS卫星状态的监听。

5.1. 创建卫星状态监听器

GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {@Overridepublic void onGpsStatusChanged(int event) {// GPS 用于报告GPS的状态变化,包含以下四种状态:// GpsStatus.GPS_EVENT_STARTED      开始GPS定位,表示GPS开始定位,注意和LocationListener中的onProviderEnabled进行区分// GpsStatus.GPS_EVENT_STOPPED      停止GPS定位,注意和LocationListener中的onProviderDisabled进行区分// GpsStatus.GPS_EVENT_FIRST_FIX    表示GPS自启动以来首次定位成功// GpsStatus.GPS_EVENT_SATELLITE_STATUS GPS卫星状态改变(定位过程中GPS的卫星状态一直处于变化中的,该方法会不断地进行回调)}
};

5.2. 监听卫星状态

GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {@Overridepublic void onGpsStatusChanged(int event) {if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {// 需要通过LocationManager拿到具体的卫星状态GpsStatus gpsStatus = locationManager.getGpsStatus(null);// 然后获取卫星状态的迭代器Iterator<GpsSatellite> iterator = gpsStatus.getSatellites().iterator();while (iterator.hasNext()) {GpsSatellite satellite = iterator.next();// 该方法获取到一个卫星的信噪比(信号噪声比),信噪比越大表示信号越强。// 通过GpsSatellite对象你可以获取到很多信息,可以直接查看GpsSatellite对象。float nr = satellite.getSnr();}}}
};

有了卫星的信噪比就可以根据信噪比的好坏去判断是否能定位成功了,正常情况下信噪比能达到30就达到了及格线,但是需要有三颗以上卫星同时及格才可以定位成功。但是测试发现,信噪比在27左右的时候也是能定位成功的只是定位时间较长。还有一点需要注意,你或许会奇怪GPS卫星明明只有14颗,为什么我收到的卫星个数甚至多于24,搞硬件的告诉我的答案是,现在的GPS天线、芯片不仅仅回去检查GPS卫星获取定位,而是直接集成了几种定位系统,随便观测到什么只要达标就能定位成功(听着意思是各卫星之间也是相互兼容的,不需要纠结,可以确认的是达标后确实能定位成功)。而且你回发现其中有一个值最大,一般是位于你头顶的那颗,如果在你头顶没有遮盖物的情况下位于你头顶的那颗信号都不行,那就信号真的很差了。

可以定位的标准为,三颗以上信噪比达到25以上。

5.3. 基于卫星状态的定位实现

于是,我们在GpsStatus.Listener中去判断卫星状态,判断达到25以上的卫星是否有3颗,有的话就进行定位,否则停止定位。代码很简单如下:

// 1. 拿到LocationManager对象
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);// 2. 创建定位监听
locationListener = new LocationListener() {@Overridepublic void onLocationChanged(Location location) {// 定位成功回调}...(省略其他三个方法)
};// 3. 创建卫星状态监听
GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {@Overridepublic void onGpsStatusChanged(int event) {if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {// 计算达标卫星个数int validSatelliteCount = 0;GpsStatus gpsStatus = locationManager.getGpsStatus(null);Iterator<GpsSatellite> iterator = gpsStatus.getSatellites().iterator();while (iterator.hasNext()) {GpsSatellite satellite = iterator.next();float nr = satellite.getSnr();if (nr > 25) {validSatelliteCount++;}}if (validSatelliteCount < 3) {// 不达标取消定位locationManager.removeUpdates(locationListener);}}}
};// 添加卫星监听开始定位
locationManager.addGpsStatusListener(gpsStatusListener);
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, locationListener, getMainLooper());

6. GPS定位方案改进版

梳理了GPS的定位流程以及相关要点,实现了一个简单版的GPS定位实现。但是这样依然不完美,GPS定位方案依然需要改进。
假设GPS需要每五分钟定位一次,使用requestLocationUpdates方法时间参数设置为5min对于普通移动设备来说显然不合适,定位失败的情况下电量消耗会过大。所以呢,我们定位方案改进如下:

考虑GPS热启动的话一般5s内可以定位成功(GPS 芯片特别差就另当别论),所以我们为GPS定位过程加上一个超时时间5s,GPS定位开始后,5s内定位成功就成功返回并关掉GPS定位,出现失败的时候,我们应该去计算刚才5s内每次卫星状态改变时是否都达到了定位标准。如果5s内有30%以上的概率达到了定位标准很可能GPS处于冷启动状态,或者GPS设备偶尔处于有遮盖物的地方,则延长定位时间直至定位成功或者卫星状态达标概率低于30%。

7. Blog 说明

  • 比较好的GPS定位方案
  • GPS没有收到定位回调 因为GPS定位很慢,并且室内信号很弱

GPS定位详解——涉及GPS版本变化、定位获取失败等常见问题。相关推荐

  1. css中的position定位详解

    css中的position定位详解 position属性指定了元素的定位类型. position属性的5个值:static,relative,fixed,absolute,sticky; 元素可以使用 ...

  2. tensorflow对应的python版本_详解Tensorflow不同版本要求与CUDA及CUDNN版本对应关系

    参考官网地址: Windows端:https://tensorflow.google.cn/install/source_windows CPU Version Python version Comp ...

  3. css 高度塌陷_HTML+CSS入门 HTML高度塌陷以及定位详解

    本篇教程介绍了HTML+CSS入门 HTML高度塌陷以及定位详解,希望阅读本篇文章以后大家有所收获,帮助大家HTML+CSS入门. < 高度塌陷的含义: 父元素的高度,默认被子元素撑开,目前来讲 ...

  4. python无法使用1号gpu_详解tensorflow2.x版本无法调用gpu的一种解决方法

    最近学校给了一个服务器账号用来训练神经网络使用,服务器本身配置是十路titan V,然后在上面装了tensorflow2.2,对应的python版本是3.6.2,装好之后用tf.test.is_gpu ...

  5. 详解redis5.x版本

    详解redis5.x版本 关系型和非关系型 关系型数据库: mysql Oracle pg 非关系型数据库: redis MongoDB esnosql not only SQL nosql 指的是非 ...

  6. c语言指定变量地址,C语言中 “_at()” 特殊地址定位详解

    C语言中 "_at()" 特殊地址定位详解 在keil里面,有一个特殊地址定位的指令,就是将一个变量或常量定位到一个指定的地址上面 指令为 __at ,使用方法如下 int var ...

  7. 定位的坐标原点HTML,css固定定位_CSS绝对定位固定定位详解

    摘要 腾兴网为您分享:CSS绝对定位固定定位详解,智学网,鱼乐贝贝,优酷,瑞易生活等软件知识,以及安卓微信多开,特效视频,微贷网app,勿忘我3dm,有为学堂,火力牛,手机知网,移动小秘书,快学堂,p ...

  8. 《MySQL安装流程详解》及《MySQL安装一直失败,重新安装显示已安装》

    <MySQL安装流程详解>及<MySQL安装一直失败,重新安装显示已安装> 本文由博主经过查阅网上资料整理总结后编写,如存在错误或不恰当之处请留言以便更正,内容仅供大家参考学习 ...

  9. python如何安装matplotlib_详解python安装matplotlib库三种失败情况

    (可能只有最后一句命令有用,可能全篇都没用) (小白方法,可能只适用于本人情况) 安装matplotlib时,出现的三种失败情况 1.read timed out 一开始我在pycharm终端使用pi ...

最新文章

  1. spring-gateway(一)Reactor编程基础
  2. css z-index层重叠顺序
  3. WebSocket 实战--转
  4. 聊聊flink的FencedAkkaInvocationHandler
  5. rgb值转换成16进制
  6. ROS2学习(十).ROS概念 - 主题的统计
  7. NB-IoT SNR RSRQ RSRP等信号参数解释
  8. 计算机软件应用员,济宁计算机办公应用软件操作员
  9. org.eclipse.birt.report.exception.ViewerException: 没有可用的报表设计对象.
  10. 如何调试CSS的跨浏览器样式bug
  11. python下载手机版-python3手机版下载
  12. 使用IIS 7.0 Smooth Streaming 优化视频服务
  13. linux执行ksh文件,关于linux:KSH shell,它对目录中的文件行进行计数
  14. Ubuntu16.04安装(QQ.exe)
  15. 当前安全设置不允许下载该文件的原因以及图文解决办法
  16. Tk应用程序:密码输入框
  17. html ---烟花
  18. 机器学习中qa测试_学会区分人工智能和机器学习,并了解QA测试方法
  19. java生成6随机数字和字母_Java生成含字母和数字的6位随机字符串
  20. flink1.13 upsert-kafka connector 实时报表 视频演示

热门文章

  1. 作为一名蒻幾对2017noip提高的反思与总结
  2. 采用jacob读取并在网页中显示ppt、word、excel
  3. Error in nnet.default(x, y, w, ...) : too many (2651) weights
  4. 简历制作 | 保研 | 考研复试
  5. c语言编程工具栏没有了,2009计算机二级C语言:工具栏,可拖动,并在被隐藏的地方显示的实现代码...
  6. 解决通过硬盘或U盘安装ubuntu server出现无法挂载光盘的问题教程
  7. [转载]推荐...推荐...破解入门教程和解密工具
  8. 家常菜做法:熬萝卜粉丝
  9. 1、查询姓名中包含‘u’字母的员工记录2、同名去重3、字段计算
  10. 《花雕学AI》07:AI脑洞大开-盘点最火爆人工智能ChatGPT的23种新颖用法