背景
在个人 App:Hi朋友
中完善天气查询功能时,需要定位用户当前所在的城市,需要用到手机的定位功能。让用户打开天气查询页时,能够自动定位当前所在城市,然后获取该城市的天气数据,是一个提升用户体验度的事情。
实现方式
- 使用集成百度或者高德地图的相关sdk
- 使用 adnroid sdk 自带的 api 来实现
- 其他
我这里使用的是第二种,为了能快速的上线第一版的个人 App,我没有集成第三方平台的 sdk。即使会出现最坏的情况:定位失败。那么也不要紧,用户还可以手动输入城市来查询对应的天气数据,只是用户体验会差那么一丢丢。后面会根据用户的一个持续反馈来决定是否有必要集成第三方平台的sdk。目前就是这么一回事。
实现关键代码
- 在 android 6.0 上对危险权限使用的申请,代码图示如下:
因为室内定位需要用到网络,所以网络权限也要在清单配置文件中申明。
这里有用的我自己封装的权限工具类,关于该工具类的简单使用请阅览 Android 危险权限使用申请 工具类 封装与简便使用 一文。
- 定位相关权限被授权后,我们就可以开始执行定位操作了,代码如下:
/**
* 定位获取当前城市
*/
private void location() {
LocationManager locationManager = (LocationManager) getContext()
.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(false);
criteria.setPowerRequirement(Criteria.POWER_LOW);
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
// String providerName = locationManager.getBestProvider(criteria, true);
// String providerName = LocationManager.NETWORK_PROVIDER;
String providerName = "";
List<String> providerList = locationManager.getProviders(true);
if (providerList.contains(LocationManager.NETWORK_PROVIDER)){
providerName = LocationManager.NETWORK_PROVIDER;
}else if (providerList.contains(LocationManager.GPS_PROVIDER)){
providerName = LocationManager.GPS_PROVIDER;
}else {
ToastUtil.showToast(getContext(), "provider 获取失败");
return;
}
// 权限复验
if (ActivityCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(getContext(),
Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ToastUtil.showToast(getContext(), "权限未授权,请先授权UHello定位权限");
return;
}
Location location = locationManager.getLastKnownLocation(providerName);
if (location != null){
final double longitude = location.getLongitude();// 经度
final double latitude = location.getLatitude();// 纬度
LogUtil.e("TAG", "longitude = " + longitude);
LogUtil.e("TAG", "latitude = " + latitude);
// 因为这里 Geocoder对象的 getFromLocation 方法,源码说明中建议在工作线程执行 getFromLocation方法
new Thread(){
@Override
public void run() {
super.run();
try {
Geocoder geocoder = new Geocoder(getContext(), Locale.getDefault());
result = geocoder.getFromLocation(latitude, longitude, 1);
handler.sendEmptyMessage(WHAT_LOCATE);
}catch (Exception e){
e.printStackTrace();
}
}
}.start();
}else {
ToastUtil.showToast(getContext(), "UHello 定位失败");
}
}
上面的代码逻辑比较简单,同学们看注释就可以理解了。
对于 handler 中的消息处理部分的代码如下图示:
而这里我采用了Geocoder 的getFromLocation方法来定位的一个功能。因为这个方法里面需要传递经度和纬度两个非常关键的参数,所以总结来说,粗略的定位其实关键的地方是要能获取当前位置的一个经纬度值。
当我们有里经纬度值后,采用上述方法就可以成功的获取定位信息了。
或者
使用百度接口(网上给出的):
http://api.map.baidu.com/geocoder?output=json&location=39.913542,116.379763&ak=esNPFDwwsXWtsQfw4NMNmur1
- 不过需要考虑最坏的情况
可能存在某些情况下,上述代码无法成功获取经纬度信息,那么可以考虑使用第三方平台的sdk,具体原因可以参考文章 使用Android自带api定位失败的原因
结果验证图示
- 经纬度logcat日志打印图如下:
- 动态gif效果图如下:
技术永不眠,我们下期见!