做項目需要獲取經(jīng)緯度信息炭晒,學習了下android自帶的定位API,簡單實現(xiàn)了一下酪耕,這里記錄一下酒繁。廢話不多說滓彰,先上代碼:
private String locationStr = "";
private String message = "";
private static final int REQUEST_CODE = 10;
private void getLocation() {
if (Build.VERSION.SDK_INT >= 23) {// android6 執(zhí)行運行時權(quán)限
if (ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// Activity#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for Activity#requestPermissions for more details.
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE);
}
}
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE);//低精度,如果設(shè)置為高精度欲逃,依然獲取不了location找蜜。
criteria.setAltitudeRequired(false);//不要求海拔
criteria.setBearingRequired(false);//不要求方位
criteria.setCostAllowed(true);//允許有花費
criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗
//獲取LocationManager
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 獲取最好的定位方式
String provider = locationManager.getBestProvider(criteria, true); // true 代表從打開的設(shè)備中查找
// 獲取所有可用的位置提供器
List<String> providerList = locationManager.getProviders(true);
// 測試一般都在室內(nèi),這里顛倒了書上的判斷順序
if (providerList.contains(LocationManager.NETWORK_PROVIDER)) {
provider = LocationManager.NETWORK_PROVIDER;
} else if (providerList.contains(LocationManager.GPS_PROVIDER)) {
provider = LocationManager.GPS_PROVIDER;
} else {
// 當沒有可用的位置提供器時稳析,彈出Toast提示用戶
Toast.makeText(this, "Please Open Your GPS or Location Service", Toast.LENGTH_SHORT).show();
return;
}
LocationListener locationListener = new LocationListener(){
//當位置改變的時候調(diào)用
@Override
public void onLocationChanged(Location location) {
//經(jīng)度
double longitude = location.getLongitude();
//緯度
double latitude = location.getLatitude();
//海拔
double altitude = location.getAltitude();
locationStr = longitude+"_"+latitude;
launcher.callExternalInterface("getLocationSuccess", locationStr);
}
//當GPS狀態(tài)發(fā)生改變的時候調(diào)用
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
switch (status) {
case LocationProvider.AVAILABLE:
message = "當前GPS為可用狀態(tài)!";
break;
case LocationProvider.OUT_OF_SERVICE:
message = "當前GPS不在服務(wù)內(nèi)!";
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
message = "當前GPS為暫停服務(wù)狀態(tài)!";
break;
}
launcher.callExternalInterface("GPSStatusChanged", message);
}
//GPS開啟的時候調(diào)用
@Override
public void onProviderEnabled(String provider) {
message = "GPS開啟了!";
launcher.callExternalInterface("GPSOpenSuccess", message);
}
//GPS關(guān)閉的時候調(diào)用
@Override
public void onProviderDisabled(String provider) {
message = "GPS關(guān)閉了!";
launcher.callExternalInterface("GPSClosed", message);
}
};
獲取定位:
//獲取上次的location
Location location = locationManager.getLastKnownLocation(provider);
/**
* 參1:選擇定位的方式
* 參2:定位的間隔時間
* 參3:當位置改變多少時進行重新定位
* 參4:位置的回調(diào)監(jiān)聽
*/
locationManager.requestLocationUpdates(provider, 10000, 0, locationListener);
while(location == null){
location = locationManager.getLastKnownLocation(provider);
}
//移除更新監(jiān)聽
locationManager.removeUpdates(locationListener);
if (location != null) { //不為空,顯示地理位置經(jīng)緯度
//經(jīng)度
double longitude = location.getLongitude();
//緯度
double latitude = location.getLatitude();
//海拔
double altitude = location.getAltitude();
locationStr = longitude+"_"+latitude;
launcher.callExternalInterface("getLocationSuccess", locationStr); } }
/**
* 獲取權(quán)限結(jié)果
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted準許
getLocation();
} else {
// Permission Denied拒絕
}
}
}
以下為代碼說明:
getLocation()方法實現(xiàn)定位的一系列操作洗做,但是安卓要調(diào)服務(wù)是需要驗證權(quán)限的,所以要復(fù)寫onRequestPermissionsResult方法彰居。
關(guān)鍵點:
//獲取上次的location
Location location = locationManager.getLastKnownLocation(provider);
獲取最近一次的有效location诚纸,如果沒有,則返回null陈惰。也就是說最近一次必須獲取過定位才能得到lastLocation畦徘。第一次登錄或者新安裝的app是會返回null的。
那么問題來了抬闯,如何獲取第一次的定位信息呢井辆?可以通過下面這個方法注冊請求新的位置信息:
locationManager.requestLocationUpdates(provider, 10000, 0, locationListener);
其中,provider 是使用的定位服務(wù)商溶握,主要有 網(wǎng)絡(luò)定位杯缺,GPS定位,直接取緩存:
LocationManager.NETWORK_PROVIDER睡榆, LocationManager.GPS_PROVIDER萍肆, LocationManager.PASSIVE_PROVIDER
LocationManager本身提供了選擇最好的provider的方法:
// 獲取最好的定位方式
String provider = locationManager.getBestProvider(criteria, true); // true 代表從打開的設(shè)備中查找
但是我在上面選擇provider時做了一個檢查的操作:
// 獲取所有可用的位置提供器
List<String> providerList = locationManager.getProviders(true);
// 測試一般都在室內(nèi),這里顛倒了書上的判斷順序
if (providerList.contains(LocationManager.NETWORK_PROVIDER)) {
provider = LocationManager.NETWORK_PROVIDER;
} else if (providerList.contains(LocationManager.PASSIVE_PROVIDER)) {
provider = LocationManager.GPS_PROVIDER;
} else {
// 當沒有可用的位置提供器時胀屿,彈出Toast提示用戶
Toast.makeText(this, "Please Open Your GPS or Location Service", Toast.LENGTH_SHORT).show();
return;
}
原因是API本身是GPS優(yōu)先的塘揣,這樣在室內(nèi)測試時會出現(xiàn)bestprovider得到的是GPS方式,但是卻無法定位的情況(室內(nèi)GPS信號很弱宿崭,基本不可用)亲铡。所以我改成了優(yōu)先選擇網(wǎng)絡(luò)定位,然后再選擇GPS定位。實際使用時可以去掉該段操作奖蔓。
另外琅摩,locationListener是注冊的監(jiān)聽事件。其中我們要關(guān)注的是
public void onLocationChanged(Location location)
這個方法會監(jiān)聽上面的requestLocationUpdates锭硼,獲取到新的位置信息就會回調(diào)該方法,所以大家可以再這個方法里處理獲取到的location蜕劝。
不過檀头,這個定位有一個很大的問題,那就是對于部分安卓設(shè)備岖沛,第一次獲取location時暑始,會在locationManager.requestLocationUpdates處堵塞,導(dǎo)致程序一直卡在這里婴削,遲遲得不到onLocationChanged的回調(diào)廊镜。我測試了安卓5,6, 7的設(shè)備唉俗,其中兩個android5.1.1的設(shè)備一直都獲取不到location嗤朴,這就導(dǎo)致該定位無法在此設(shè)備上使用。查了各種網(wǎng)站虫溜,發(fā)現(xiàn)有兩個網(wǎng)友遇到了同樣的問題雹姊,但是取沒有解決:https://segmentfault.com/q/1010000004477439/a-1020000006144410。
而且有一個奇怪的現(xiàn)象衡楞,就是我在android5.1.1的設(shè)備上測試的時候吱雏,偶爾是可以得到一次location的,但這個幾率極低瘾境。網(wǎng)上有說需要等待一段時間歧杏,但是我等了個把小時都不行。
另外我也試了google的FusedLocationProviderClient方法迷守,也是堵塞在requestLocationUpdates犬绒,實在是郁悶。由于我做的是一個海外的項目盒犹,所以什么百度API懂更,騰訊API就不用想了。
這里貼出來也是希望大神們看到之后能夠指正急膀,并希望能幫忙解決上面這個問題沮协,大家共同進步。
您的贊賞是我堅持分享的最大動力 :)