Android百度地图(一):百度地图定位sdk 类方法参数、定位原理详细介绍

转载、引用请标明出处
http://www.jianshu.com/p/29ccac3e1e42
本文出自zhh_happig的简书博客,谢谢

Android百度地图(二):百度地图sdk显示位置点、图层绘制
Android百度地图(三):百度地图画运动轨迹及图层点击事件处理
Android百度地图(四):百度地图运动轨迹纠偏、去噪、绑路之百度鹰眼sdk服务
Android百度地图(五):百度地图鹰眼sdk监控进出地理围栏(区域)
Android百度地图(六):百度地图POI检索,行政区边界、公交、线路规划查询,地理编码介绍

本文主要针对百度定位sdk的api进行详细说明、注意事项,还会简单的谈一下定位的原理,目的是让读者真正了解定位,只有在完全了解的情况下,在开发中才会少走弯路,少踩坑。

一 定位简介

目前定位大致分为三种:gps定位、wifi定位、基站定位

gps定位:卫星定位,利用手机gps硬件定位,实现简单,手机本地就能实现定位,不需要和服务端进行交互。

//伪代码
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5, listener);

手机GPS状态说明


以小米手机为例。如上图GPS标识为高亮状态,代表gps已经开启,可进行gps定位

如上图红框内灰暗标识,说明gps正在搜索卫星信号,虽然此时已经开始gps定位,但 是不会有gps位置返回,直到搜索到至少4颗卫星信号,才能定位成功;在室外开阔地 搜星的过程几分钟到十几分钟都有可能,如果gps长时间无法定位,尝试重启手机

如上图红框内gps标识变成高亮,说明gps已经搜索到卫星信号,开始了正常定位

在桥梁下、大树下、建筑物内、隧道内,手机很多时候都无法接收到gps信号,就无法利用gps定位了。
在室内无法定位是gps定位的最大问题,此时就得利用WiFi定位了。

wifi定位:一说到wifi定位,很多人觉得奇怪,WiFi怎么能知道我的位置呢,wifi硬件会返回位置吗?其实这些WiFi都不能做到。wifi定位的原理是,我们在室外的时候,手机能接收到gps位置信息,也能扫描到WiFi,当手机把gps位置和WiFi传到后端服务器,WiFi和gps位置就建立了映射关系,当手机在室内无法接收到gps时,却能扫描WiFi,手机把WiFi传到服务器查询出对应的gps位置,然后进行计算可以得到位置结果(经纬度),其中映射和计算是很复杂的过程,感兴趣的同学可以查阅相关资料。wifi定位需要wifi开启,并且手机能上网。

基站定位:当手机无法扫描到WiFi时,只要装了sim卡,就能连接移动或联通等基站,即可用基站定位,定位原理和WiFi大致相同。基站定位需要装了sim卡,并且手机能上网。

wifi定位与基站定位统称为网络定位,当wifi关闭,或者扫描不到WiFi列表时,sdk只会把获取的基站信息发给服务端,进行基站定位;如果没有sim,wifi开启,则sdk会把扫描到的WiFi信息发给服务端,进行wifi定位;如果既有wifi又有基站,则sdk会把这两者信息都发给服务端,具体用哪一种定位,不太确定,但绝大多数情况下都是用wifi定位的。

在室内无gps时,百度定位就是利用的WiFi和基站定位的,在室外有gps时,百度是利用的android自带的LocationManager进行定位,当然室外也可以用WiFi基站定位。

gps定位精度很高,几米到十几米,但是耗电严重;
WiFi定位精度相对于gps差一点,但是也能到十几米、几十米,也有上百米的误差的,低耗电;
基站定位精度很差,一般都有几百米,上千米的误差。
这个误差其实和wifi、基站的信号覆盖半径有关,wifi覆盖半径大概100m左右,而基站的覆盖半径就到km级别了。

二 百度定位sdk配置

1.必须申请apikey

<meta-data
  android:name="com.baidu.lbsapi.API_KEY"
  android:value="P9XLjU5FvdtDhRUTumdg2xRTpmk*****" />

每个apikey对应一个唯一的应用,这个apikey的主要作用是统计每个应用每天的定位次数,虽然百度没有说明每天的访问次数,但是应该有一个访问次数。比如恶意攻击,设置访问次数可防止恶意攻击。

2.导入jar、库文件
BaiduLBS_Android.jar:提供定位sdk的api
liblocSDK7a.so:这个so文件的主要作用是对客户端发送给服务端的参数数据进行加密
开发包下载地址,选择基础定位即可。

3.设置AndroidManifest.xml

<service
  android:name="com.baidu.location.f"
  android:enabled="true"
  android:process=":remote" >
  <intent-filter>
    <action
      android:name="com.baidu.location.service_v2.2">
    </action>
  </intent-filter>
</service>

周期性的定位请求是在这个服务中发起的,如果不声明这个Service,周期性请求无法正常工作,但可进行一次定位。

4.声明使用权限

<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<!-- 用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SD卡读取权限,用户写入离线定位数据-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>

注:以上介绍和配置,高德、腾讯sdk也差不多是这样的,这些sdk不一样的就是下面的api不一样,但是定位原理流程都是大同小异的

三 定位api详解

1.初始化LocationClient类
此处需要注意:LocationClient类最好在主线程中声明,需要Context类型的参数。
Context需要时全进程有效的Context,推荐用getApplicationConext获取全进程有效的Context

//伪代码
public LocationClient mLocationClient = null;;
public void onCreate()
{
  mLocationClient = new LocationClient(getApplicationContext());//声明LocationClient类
  mLocationClient.registerLocationListener(myListener);//注册监听函数
 }

2.配置定位SDK参数
设置定位参数包括:定位模式(高精度定位模式、低功耗定位模式和仅用设备定位模式),返回坐标类型,是否打开GPS,是否返回地址信息、位置语义化信息、POI信息等等。
LocationClientOption类,该类用来设置定位SDK的定位方式,例如:

//伪代码
LocationClientOption mOption = new LocationClientOption();

/**
* 默认高精度,设置定位模式
* LocationMode.Hight_Accuracy 高精度定位模式:这种定位模式下,会同时使用
  网络定位(Wi-Fi和基站定位)和GPS定位,优先返回最高精度的定位结果;
  但是在室内gps无信号,只会返回网络定位结果;
  室外如果gps收不到信号,也只会返回网络定位结果。
* LocationMode.Battery_Saving 低功耗定位模式:这种定位模式下,不会使用GPS,只会使用网络定位。
* LocationMode.Device_Sensors 仅用设备定位模式:这种定位模式下,
  不需要连接网络,只使用GPS进行定位,这种模式下不支持室内环境的定位
*/
mOption.setLocationMode(LocationMode.Hight_Accuracy);

/**
* 默认是true,设置是否使用gps定位
* 如果设置为false,即使mOption.setLocationMode(LocationMode.Hight_Accuracy)也不会gps定位
*/
mOption.setOpenGps(true);

/**
* 默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll;
* 目前国内主要有以下三种坐标系:
1. wgs84:目前广泛使用的GPS全球卫星定位系统使用的标准坐标系;
2. gcj02:经过国测局加密的坐标;
3. bd09:为百度坐标系,其中bd09ll表示百度经纬度坐标,bd09mc表示百度墨卡托米制坐标;
* 在国内获得的坐标系类型可以是:国测局坐标、百度墨卡托坐标 和 百度经纬度坐标。
  在海外地区,只能获得WGS84坐标。请在使用过程中注意选择坐标。
*/
mOption.setCoorType("bd09ll");

/**
* 默认0,即仅定位一次;设置间隔需大于等于1000ms,表示周期性定位
* 如果不在AndroidManifest.xml声明百度指定的Service,周期性请求无法正常工作
* 这里需要注意的是:如果是室外gps定位,不用访问服务器,设置的间隔是3秒,那么就是3秒返回一次位置
  如果是WiFi基站定位,需要访问服务器,这个时候每次网络请求时间差异很大,设置的间隔是3秒,
  只能大概保证3秒左右会返回就一次位置,有时某次定位可能会5秒才返回
*/
mOption.setScanSpan(3000);

/**
* 默认false,设置是否需要地址信息
* 返回省、市、区、街道等地址信息,这个api用处很大,
  很多新闻类app会根据定位返回的市区信息推送用户所在市的新闻
*/
mOption.setIsNeedAddress(true);

/**
* 默认false,设置是否需要位置语义化结果
* 可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
*/
mOption.setIsNeedLocationDescribe(true);

/**
* 默认false,设置是否需要设备方向传感器的方向结果
* 一般在室外gps定位时,返回的位置信息是带有方向的,但是有时候gps返回的位置也不带方向,
  这个时候可以获取设备方向传感器的方向
* wifi基站定位的位置信息是不带方向的,如果需要可以获取设备方向传感器的方向
*/
mOption.setNeedDeviceDirect(false);

/**
* 默认false,设置是否当gps有效时按照设定的周期频率输出GPS结果
* 室外gps有效时,周期性1秒返回一次位置信息,其实就是设置了
locationManager.requestLocationUpdates中的minTime参数为1000ms,1秒回调一个gps位置
* 如果设置了mOption.setScanSpan(3000),那minTime就是3000ms了,3秒回调一个gps位置
*/
mOption.setLocationNotify(false);

/**
* 默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
* 如果你已经拿到了你要的位置信息,不需要再定位了,不杀死留着干嘛
*/
mOption.setIgnoreKillProcess(true);

/**
* 默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
* POI就是获取到的位置附近的一些商场、饭店、银行等信息
*/
mOption.setIsNeedLocationPoiList(true);

/**
* 默认false,设置是否收集CRASH信息,默认收集
*/
mOption.SetIgnoreCacheException(false);

/**
* 默认false,设置定位时是否需要海拔高度信息,默认不需要,除基础定位版本都可用
*/
mOption.setIsNeedAltitude(false);

mLocationClient.setLocOption(mOption);//设置定位参数
mLocationClient.start();//开始定位

3.实现BDLocationListener接口
BDLocation类,封装了定位SDK的定位结果,在BDLocationListener的onReceiveLocation方法中获取,onReceiveLocation方法当返回的是网络类型定位时是在子线程中执行了,如果有UI操作,请注意。

//伪代码
private BDLocationListener myListener = new BDLocationListener() {

  @Override
  public void onReceiveLocation(BDLocation location) {
    //定位sdk获取位置后回调
    if (null != location && location.getLocType() != BDLocation.TypeServerError) {
                
      /**
      * location.getTime() 是指服务端出本次结果的时间,如果位置不发生变化,则时间不变
      */
      location.getTime();
    
      /**
      * 定位类型
      BDLocation.TypeGpsLocation----gps定位
      BDLocation.TypeNetWorkLocation----网络定位(wifi基站定位)
      以及其他定位失败信息
      */
      location.getLocType();
                
      /**
      * 对应的定位类型说明
      * 比如"NetWork location successful"之类的信息
      */
      location.getLocTypeDescription();
                
      /**
      * 纬度
      */
      location.getLatitude();
                
      /**
      * 经度
      */
      location.getLongitude();
                
      /**
      * 误差半径,代表你的真实位置在这个圆的覆盖范围内,
      * 半径越小代表定位精度越高,位置越真实
      * 在同一个地点,可能每次返回的经纬度都有微小的变化,
      * 是因为返回的位置点并不是你真实的位置,有误差造成的。
      */
      location.getRadius();
                
      location.getCountryCode();//国家码,null代表没有信息
      location.getCountry();//国家名称
      location.getCityCode();//城市编码
      location.getCity();//城市
      location.getDistrict();//区
      location.getStreet();//街道
      location.getAddrStr();//地址信息
      location.getLocationDescribe();//位置描述信息
                
      /**
      * 判断用户是在室内,还是在室外
      * 1:室内,0:室外,这个判断不一定是100%准确的
       */
      location.getUserIndoorState();
                
      /**
      * 获取方向
      */
      location.getDirection();
                
      if (location.getPoiList() != null && !location.getPoiList().isEmpty()) {
        for (int i = 0; i < location.getPoiList().size(); i++) {
          Poi poi = (Poi) location.getPoiList().get(i);
          poi.getName();//获取位置附近的一些商场、饭店、银行等信息
        }
      }
                
      if (location.getLocType() == BDLocation.TypeGpsLocation) {// GPS类型定位结果
        location.getSpeed();//速度 单位:km/h,注意:网络定位结果是没有速度的
        location.getSatelliteNumber();//卫星数目,gps定位成功最少需要4颗卫星
        location.getAltitude();//海拔高度 单位:米
        location.getGpsAccuracyStatus();//gps质量判断
      } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {//网络类型定位结果
        if (location.hasAltitude()) {//如果有海拔高度
          location.getAltitude();//单位:米
        }
        location.getOperators();//运营商信息
      } else if (location.getLocType() == BDLocation.TypeOffLineLocation) {// 离线定位结果
        //离线定位成功,离线定位结果也是有效的;
      } else if (location.getLocType() == BDLocation.TypeServerError) {
        //服务端网络定位失败,可以反馈IMEI号和大体定位时间到loc-bugs@baidu.com;
      } else if (location.getLocType() == BDLocation.TypeNetWorkException) {
        //网络不同导致定位失败,请检查网络是否通畅;
      } else if (location.getLocType() == BDLocation.TypeCriteriaException) {
        //无法获取有效定位依据导致定位失败,一般是由于手机的原因,处于飞行模式下一般会造成这种结果,可以试着重启手机;
      }
    }
  }

};

4.定位完成注意释放资源

//伪代码
protected void onStop() {
  mLocationClient.unregisterListener(myLocationListener); //注销掉监听
  mLocationClient.stop(); //停止定位
}

仅一次定位:
mLocationClient.start()启动定位SDK,在BDLocationListener的onReceiveLocation方法中获取到位置后,
再 mLocationClient.stop()关闭定位SDK即可。
周期性定位:
设置周期间隔,单位ms,必须大于等于1000ms才进行周期性定位,小于1000只定位一次。
locationClientOption .setScanSpan(1000);
mLocationClient.start();
每次获取位置都会在BDLocationListener的onReceiveLocation方法中回调,
不再进行定位, mLocationClient.stop()关闭定位SDK。

四 定位错误分析

首先,一定确定你的配置都完成了:
1.apikey申请正确,并在AndroidManifest.xml配置;
2.权限都申请了,注意6.0权限的动态申请;
3.AndroidManifest.xml中定位服务配置了;
4.jar包以及so包都导入了。
在Android Studio除了上述操作之外,还需要在build.gradle中配置SO文件的使用,如下所示

android{
    ...
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

另外,ABI:指应用基于哪种指令集来进行编译,ABI分armeabi、armeabi-v7a、mips、x86、x86_64等,它们都是表示cpu的类型,确定自己的机器是什么类型的cpu,导入相应的so文件。

如果所有配置正确,在a手机中正常,在b手机出错了,原因很有可能就是ab手机的cpu类型不同导致的。

查看cpu类型命令
1、adb shell
2、cat /proc/cpuinfo

详细cpu间so文件的兼容问题,请阅读相关资料

如果确定所有配置正确,还有问题,则需要通过获取定位返回错误码分析错误原因
bDLocation.getLocType ( );//获取错误码

返回值:
61 : GPS定位结果,GPS定位成功。
62 : 无法获取有效定位依据(wifi基站信息),定位失败,请检查运营商网络或者WiFi网络是否正常开启,尝试重新请求定位。
63 : 网络异常,没有成功向服务器发起请求,请确认当前测试手机网络是否通畅,尝试重新请求定位。
65 : 定位缓存的结果。
66 : 离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果。
67 : 离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果。
68 : 网络连接失败时,查找本地离线定位时对应的返回结果。
161: 网络定位结果,网络定位成功。
162: 请求串密文解析失败,一般是由于客户端SO文件加载失败造成,请严格参照开发指南或demo开发,放入对应SO文件。
167: 服务端定位失败,请您检查是否禁用获取位置信息权限,尝试重新请求定位。
502: AK参数错误,请按照说明文档重新申请AK。
505:AK不存在或者非法,请按照说明文档重新申请AK。
601: AK服务被开发者自己禁用,请按照说明文档重新申请AK。
602: key mcode不匹配,您的AK配置过程中安全码设置有问题,请确保:SHA1正确,“;”分号是英文状态;且包名是您当前运行应用的包名,请按照说明文档重新申请AK。
501~700:AK验证失败,请按照说明文档重新申请AK。

如果以上都不能解决你定位sdk使用中出现的问题,可以去百度定位sdk开发社区查阅或发帖询问,有百度工程师解答。

如果各位看官觉得文章不错,别忘了点个喜欢。
源码下载地址

以上文章内容,是本人工作中的总结,供大家参考,有误的地方还请指正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,504评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,898评论 1 300
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,218评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,322评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,693评论 3 290
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,812评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,747评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,476评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,700评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,190评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,541评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,206评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,129评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,903评论 0 199
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,894评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,748评论 2 274

推荐阅读更多精彩内容