背景
在個人 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效果圖如下:
技術永不眠,我們下期見!