高德逆地理编码接口返回数据格式不统一以及百度逆地理编码接口返回数据解析失败的踩坑记录
最近有个需求是定位后根据定位的经纬度获取当前地址的详细信息,例如获取街道名称,街道号,乡镇街道编码,区域编码等信息。
于是乎找到了高德的逆地理编码接口,看了看正好符合我的需求。然而使用起来并不顺利!
由于我使用的Retrofit,正常情况下都是直接将json自动解析成实体类,但是由于接口返回的数据格式不规范,导致我遇见的一些问题,下面记录一下解决办法,希望能帮到你。
高德逆地理编码接口返回数据格式不一致的坑
官方接口地址:高德逆地理编码
文档上的使用说明很简单,于是美滋滋的按照文档来实现了。
测试的也没问题,都能正常获取的相关信息。
正常情况下接口返回的数据:
{"status": "1","regeocode": {"addressComponent": {"city": [],"province": "上海市","adcode": "310112","district": "闵行区","towncode": "310112008000","streetNumber": {"number": "490号","location": "121.284975,31.2019319","direction": "西","distance": "2756.74","street": "金丰路"},"country": "中国","township": "新虹街道","businessAreas": [{"location": "121.30079,31.22569","name": "华漕","id": "310112"}, {"location": "121.286159,31.175343","name": "徐泾","id": "310118"}],"building": {"name": [],"type": []},"neighborhood": {"name": [],"type": []},"citycode": "021"},"formatted_address": "上海市闵行区新虹街道申长路爱博一村"},"info": "OK","infocode": "10000"
}
然而,版本发布后,工作人员外出使用时,进行逆地理编码时app一直提示数据解析失败。
我擦嘞,这是什么情况?数据解析失败那就是接口返回的数据跟实体类匹配不上呗,然后跟踪错误日志发现,果然是是数据格式不对。
下面是当高德获取不到乡镇级别的数据时返回的接口:
{"status": "1","regeocode": {"addressComponent": {"city": [],"province": "上海市","adcode": "310118","district": "青浦区","towncode": "310118001000","streetNumber": {"number": [],"direction": [],"distance": [],"street": []},"country": "中国","township": "夏阳街道","businessAreas": [[]],"building": {"name": [],"type": []},"neighborhood": {"name": [],"type": []},"citycode": "021"},"formatted_address": "上海市青浦区夏阳街道盈港东路新青浦佳园(华科路)"},"info": "OK","infocode": "10000"
}
可以看到,addressComponent中的streetNumber里的字段值居然变成了空数组!
这不是扯淡么,你获取不到就获取不到呗,直接返回个空字符串也行啊,有值的时候返回字符串,无值的时候居然返回的是个空数组,这叫我怎么解析?
最关键的是文档上居然没有说明这个情况,我也是醉了!
于是乎赶紧给高德平台进行反馈,给的答复是在有些场景下,无法确定乡镇级别地址,所以导致乡镇级别的数据有可能是空值,
数据格式不一致是由于设计的问题,但是高德表示无法修改,这就很难受了,只能自己处理了。
当时能想到的方法就是将返回数据格式类型设置为xml,解析xml就可以了。
但是我的需求是希望尽量能获取到街镇级别的数据,这样一来用户就无需手动填写了。于是乎,想到了百度,本以为高德获取不到,那百度应该也获取不到。
然而,同样的地址,百度却可以获取的到,而且百度接口返回的数据格式是规范的。
于是乎就打算将接口更改为百度的接口,但是,百度也有问题!
百度逆地理编码接口返回数据不是json,而是js,导致无法正常解析
百度逆地理编码
首先百度的文档写的还是很详细的,包括返回数据的字段类型也标清楚了,而且百度的逆地理编码好像要更强大一些,同样的位置,高德获取不到,但是百度能获取到,并且结果也很精确。但是,我发现百度的接口返回的数据没有乡镇街道编码,只有区划代码,于是乎,又给百度进行反馈
百度给出明确答复,表示暂不支持!
我尼玛,一个逆地理编码就这么难弄?
这样一来,只能是高德和百度两个接口结合使用了。
而且百度接口不知道为什么,返回的数据居然是个js!而不是json。
这就导致了在使用百度接口时一直提示一下错误
onErrorcom.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
这个是由于百度返回的接口数据不是一个严格的json数据导致的,
onErrorcom.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
解决办法,创建GsonConverterFactory的时候手动传一个Gson对象进去,并开启非严格模式
这个解决完之后,解析数据时又报一下错误,表示解析返回的json数据不正确
Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
这个应该就是因为返回的是js,而不是json数据导致的,看来,百度的接口是不能使用Retrofit对数据进行自动解析了。
高德百度两个接口相结合来满足需求
了解了高德和百度接口各自的问题后,我采用了高德和百度两个接口相结合的方式来获取详细的地址信息,由于百度的接口返回的数据比高德更精确且更规范,那么主要就采用百度的数据,至于乡镇街道编码则使用高德的数据进行补充, 如果你不用必须获取乡镇街道编码这个数据,那么,完全可以只使用百度的接口就能满足你的需求。
因为最终的数据是从两个接口返回的数据合并来的,所以,第一反应就是用RxJava中的zip操作符。
下面是实现步骤:
1.首先新建实体类,把需要的字段定义好
/*** @description: 详细的定位信息* @author : yzq* @date : 2019/4/12* @time : 10:49**/data class LocationDetailsBean(var adcode: String = "", // 310118var city: String = "", // 上海市var country: String = "", // 中国var district: String = "", // 青浦区var province: String = "", // 上海市var street: String = "", // 浦仓路var streetNumber: String = "", // 567号var town: String = "",//盈浦街道var townCode: String = "")
2.先使用高德定位进行定位拿到经纬度数据,由于我这边主要用的是高德的API,所以定位也是高德的,这里定位代码我就省略了。
3.请求百度的逆地理编码接口
由于百度接口直接返回的是js,所以无法正常使用Retrofit的自动解析,这里我就使用OkHttpClient请求手动转了
/*** 百度逆地理编码* @param location LocationBean * @return Observable<BaiduRegeoBean> */fun getBaiduRegeo(location: LocationBean): Observable<BaiduRegeoBean> {return Observable.create<BaiduRegeoBean> { emitter ->LogUtils.i("百度逆地理编码接口")val httpClient = OkHttpClient()val httpUrl = HttpUrl.parse(Urls.BAIDU_REGEO)!!.newBuilder().addQueryParameter("location", "${location.latitude},${location.longitude}").addQueryParameter("coordtype", "gcj02ll").addQueryParameter("ak", "你申请的ak值").addQueryParameter("output", "json").addQueryParameter("extensions_town", "true").addQueryParameter("latest_admin", "1").build()// LogUtils.i("httpUrl:${httpUrl.query()}")val request = Request.Builder().url(httpUrl).build()// LogUtils.i("开始请求")val response = httpClient.newCall(request).enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {emitter.onError(e)emitter.onComplete()}override fun onResponse(call: Call, response: Response) {if (response.isSuccessful) {val data = response.body()!!.string()val baiduRegeoBean = Gson().fromJson<BaiduRegeoBean>(data, BaiduRegeoBean::class.java)emitter.onNext(baiduRegeoBean)emitter.onComplete()}}})}}
这样一来我们就获取到了百度逆地理编码返回的数据了,实体类自己定义即可,这里就不浪费篇幅了。
4.请求高德逆地理编码接口
/*** 高德逆地理编码* @param map Map<String, String>* @return Observable<GaodeRegeoBean>*/fun getGaodeRegeo(location: LocationBean): Observable<GaodeRegeoBean> {val longitude = String.format("%.5f", location.longitude)val latitude = String.format("%.5f", location.latitude)val map = mutableMapOf<String, String>()map.put("key", "你的key")map.put("location", "${longitude},${latitude}")map.put("radius", "3000")map.put("output", "JSON")return RetrofitFactory.instance.getService(ApiService::class.java).regeo(Urls.GAODE_REGEO, map)}
请求高德你地理编码接口正常使用Retrofit方式即可,需要注意的是,实体类中不要写 StreetNumber 相关的字段,否则就会出现数据解析失败的问题,我们这里其实只需要towncode这个字段的值,其他的字段都不需要解析
/*** @description: 高德逆地理编码接口返回的数据实体类* @author : yzq* @date : 2019/4/15* @time : 16:01* */data class GaodeRegeoBean(var info: String = "", // OKvar infocode: String = "", // 10000var regeocode: Regeocode = Regeocode(),var status: String = "" // 1
) {data class Regeocode(var addressComponent: AddressComponent = AddressComponent(),@SerializedName("formatted_address")var formattedAddress: String = ""// 上海市闵行区梅陇镇春申路1235号春申创意园B座) {data class AddressComponent(var adcode: String = "", // 310112var citycode: String = "", // 021var country: String = "", // 中国var district: String = "", // 闵行区var province: String = "", // 上海市// var streetNumber: StreetNumber = StreetNumber(),var towncode: String = "", // 310112108000var township: String = "" // 梅陇镇)}
}
5.使用Rxjava的zip操作符进行请求,然后将数据合并成我们需要的数据
Observable.zip(editUnitInfoModel.getBaiduRegeo(location),editUnitInfoModel.getGaodeRegeo(location),BiFunction<BaiduRegeoBean, GaodeRegeoBean, LocationDetailsBean> { baidu, gaode ->val locationDetailsBean = LocationDetailsBean()if (baidu.status == 0) {val baiduAddressComponent = baidu.result.addressComponentlocationDetailsBean.adcode = baiduAddressComponent.adcodelocationDetailsBean.city = baiduAddressComponent.citylocationDetailsBean.country = baiduAddressComponent.countrylocationDetailsBean.district = baiduAddressComponent.districtlocationDetailsBean.province = baiduAddressComponent.provincelocationDetailsBean.street = baiduAddressComponent.streetlocationDetailsBean.streetNumber = baiduAddressComponent.streetNumberlocationDetailsBean.town = baiduAddressComponent.town}if (gaode.status == "1") {locationDetailsBean.townCode = gaode.regeocode.addressComponent.towncode}LogUtils.i("合并后的定位信息为:${locationDetailsBean}")return@BiFunction locationDetailsBean})
最终打印的结果
这样一来就满足我的需求了。
好了,关于高德逆地理编码和百度逆地理编码接口的才坑记录就到这了。
如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!
高德逆地理编码接口返回数据格式不统一以及百度逆地理编码接口返回数据解析失败的踩坑记录相关推荐
- php接口 汉字出错 空,php接口开发时,数据解析失败问题,字符转义,编码问题(示例代码)...
php接口开发时,数据解析失败问题,字符转义,编码问题 情景: A平台--->向接口请求数据---->接口向B平台请求数据---->B平台返回数据给接口---->接口返回数据给 ...
- 前端跳转失败,例如返回按钮,js跳转失败的踩坑原因之一
本人最新博客地址blog 问题描述: 今天在做项目的一些小细节的完善,具体是这样的: 上面蓝色的按钮是用来返回至上一个页面并刷新使用的,然后js的代码是 <div class="&qu ...
- 踩坑记录:请求接口status返回0
欢迎关注博主博客: https://lvsige.top/ 现象: H5请求openapi接口,ios可以正常请求,返回200. 但是安卓请求接口返回0 用户通过"领取链接"扫码进 ...
- 股票历史数据下载接口踩坑记录
这里分享些下载财经数据下载接口的一些经验,大家可以参考下 1.如何提升接口下载速度 实际上歪枣网后台查库速度是非常快的,查库时间是有监控的,如果是查库变慢了,歪哥会进行优化.但是很多时间接口数据下载的 ...
- libx264编码过程中修改码率踩坑记录
问题来源于项目中的一个需求,根据当前网络环境实时调整libx264的码率参数,从而让视频播放更加流畅. 1.设置码率调整算法为ABR. 2.初始化,并提供一个接口供探测网络环境的线程调用.写法大概类似 ...
- (自用防再踩坑记录1)实现名字直接转化为拼音并添加入接口
首先安装汉字转拼音的第三方包,十分好用的包> pip install xpinyin 在serializers.py中的相应的serializer中添加如下代码: from xpinyin im ...
- JMeter录制不到接口(踩坑记录)
问题描述: JMeter启用代理服务器录制脚本时,web页面无法正常加载或抓取不到接口,只能获取部分静态文件. 原因分析: JMeter证书过期导致,JMeter的证书(ApacheJMeterTem ...
- Android高德地图踩坑记录-内存泄漏问题
1.问题现象 最近做项目优化,在查找app可能存在的内存泄漏地方,项目中有用到高德地图SDK,有一个页面有展示地图,每次退出该页面的时候,LeakCanary老是提示有内存泄漏,泄漏的大概信息如下: ...
- idea easyYapi插件导入yapi接口使用及踩坑记录
正常版本操作过程: 1.安装easyYapi插件: 插件拦搜索easyYapi安装并重启idea 2. 配置easyYapi 进入路径: window系统路径:File-Settings ---> ...
最新文章
- java8u211_jre864位u211
- python自己创建模块_创建并发布自己的python模块
- 微信小程序中base64转换成图片;uni-app小程序base64转图片;微信小程序base64文件转图片;微信小程序base64图片转图片
- java 减少内存_java – 减少内存流失的方法
- html渐变显示动画效果,使用CSS transition和animation改变渐变状态
- SonarQube遇到的启动问题及解决方案
- Vue slot用法(2018.09.05 星期三)
- 圈圈教你玩usb第一版硬件实物图
- 传智播客ajax视频教程 百度云,传智播客AJAX视频资料分享
- python求两坐标距离_如何使用Python已知两坐标求距离?
- 张小龙:微信产品观(下)
- PointOperation03_Matlab灰度gray图反色(inverting)
- JavaScript+css+html鼠标指针经过某些元素时背景变色
- 微软bi报表服务器,升级 Power BI 报表服务器
- 杨涛鸣 杨焘鸣:世界各个角落都存在人脉关系
- 纯代码蓝色理想的logo
- python图像处理:核磁共振图像(3D)的缩放
- python爬虫需要哪些基础知识-【PYTHON】【爬虫】关于python爬虫的一些基础知识
- 绕过CDN查找真实IP方法总结
- 方舟服务器 mod文件夹,方舟mod文件夹应该放在哪 | 手游网游页游攻略大全