關(guān)于Android實現(xiàn)定位的問題網(wǎng)上一搜會有很多代碼诡宗,但前段時間在做定位時還是遇到一些坑昙啄,記錄一下吧~
1伍绳、location一直為null
2民镜、權(quán)限動態(tài)申請
定位我們使用的一般有兩種:GPS定位、網(wǎng)絡(luò)定位适肠,GPS定位這里先埋一個坑霍衫,后面會提到。先來看一下我一開始寫的定位代碼:
private void getLocation(Context context) {
//獲取地理位置管理器
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
locationProvider=LocationManager.GPS_PROVIDER;
}else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)){
locationProvider=LocationManager.NETWORK_PROVIDER;
}else {
// TODO: 2017/12/6
ToastUtil.showShort("請打開手機定位~");
}
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null;
}
Location location=locationManager.getLastKnownLocation(locationProvider);
if (location!=null){
LogUtil.i("location","經(jīng)緯度:"+location.getLatitude()+"侯养,"+location.getLongitude());
}
}
代碼運行后得到的location始終為空敦跌,有人說getLastKnownLocation()獲取的是上一次的定位信息,第一次運行為null是可能的逛揩,要做的就是注冊監(jiān)聽器獲取更新的location柠傍,于是添加了如下代碼:
LocationListener locationListener = new LocationListener() {
// Provider的狀態(tài)在可用麸俘、暫時不可用和無服務(wù)三個狀態(tài)直接切換時觸發(fā)此函數(shù)
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
// Provider被enable時觸發(fā)此函數(shù),比如GPS被打開
@Override
public void onProviderEnabled(String provider) {
}
// Provider被disable時觸發(fā)此函數(shù)携兵,比如GPS被關(guān)閉
@Override
public void onProviderDisabled(String provider) {
}
// 當(dāng)坐標(biāo)改變時觸發(fā)此函數(shù)疾掰,如果Provider傳進相同的坐標(biāo),它就不會被觸發(fā)
@Override
public void onLocationChanged(Location location) {
LogUtil.i("location","經(jīng)緯度:"+location.getLatitude()+"徐紧,"+location.getLongitude());
}
};
mLocationManager.requestLocationUpdates(serviceProvider, 10000, 1, this);
但是静檬,運行后onLocationChanged一直沒有被調(diào)用,仍無法獲取location并级。
所以為什么location一直為null拂檩?
通過打出來的日志我們能看到是通過GPS定位的,GPS定位雖然開啟嘲碧,但是測試時我們身處室內(nèi)稻励,在室內(nèi)GPS是基本定不到位的。
所以在 if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))時我們拿到的locationProvider是gps愈涩,但由于在室內(nèi)所以location一直為null望抽。所以以上代碼邏輯是不完善的。修改后的代碼:
/**
* 獲取當(dāng)前Location
*/
private Location getLocation(Context context) {
//獲取地理位置管理器
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (!gpsEnabled() && !netWorkEnabled()) {
ToastUtil.showShort("請打開手機定位~");
}
if (gpsEnabled() && getGPSLocation(locationManager) != null) {
return getGPSLocation(locationManager);
} else if (netWorkEnabled() && getNetWorkLocation(locationManager) != null) {
return getNetWorkLocation(locationManager);
} else {
return null;
}
}
private boolean gpsEnabled() {
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
private boolean netWorkEnabled() {
return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
private Location getGPSLocation(LocationManager locationManager) {
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null;
}
return locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
private Location getNetWorkLocation(LocationManager locationManager) {
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return null;
}
return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
判斷GPS定位是否可用且得到的location不為null時履婉,使用GPS定位獲取定位信息煤篙,不成立時則判斷網(wǎng)絡(luò)定位是否可用及其location是否為null,這里就不會出現(xiàn)室內(nèi)GPS可用但無法定位的問題毁腿,在室內(nèi)可使用網(wǎng)絡(luò)定位辑奈。
對于定位服務(wù)關(guān)閉時,我們可以跳轉(zhuǎn)去設(shè)置界面去開啟:
if (!gpsEnabled() && !netWorkEnabled()) {
ToastUtil.showShort("請打開手機定位~");
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, 0);
}
在onActivityResult中再處理設(shè)置完成返回后的操作已烤。
動態(tài)申請定位權(quán)限問題
6.0以后對于Dangerous Permission類的權(quán)限(一般是涉及到用戶隱私的)鸠窗,需要用戶進行授權(quán),定位權(quán)限就是這一類權(quán)限胯究。
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
1稍计、首先在AndroidManifest文件中添加需要的以上兩個權(quán)限。
2裕循、權(quán)限檢查:checkSelfPermission臣嚣,主要用于檢測某個權(quán)限是否已經(jīng)被授予,方法返回值為PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED费韭。當(dāng)返回DENIED就需要進行申請授權(quán)了。
public boolean hasPermission(String... permissons) {
for (String permisson : permissons) {
if ((ContextCompat.checkSelfPermission(getContext(),
permisson) != PackageManager.PERMISSION_GRANTED)) {
return false;
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//適配小米機型
AppOpsManager appOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
int checkOp = appOpsManager.checkOp(AppOpsManager.OPSTR_FINE_LOCATION, Process.myUid(), getContext().getPackageName());
if (checkOp != AppOpsManager.MODE_ALLOWED) {
return false;
}
}
return true;
}
3庭瑰、申請授權(quán):requestPermissions
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, requestCode);
fragment中用requestPermissions星持,activity中用ActivityCompat.requestPermissions(...),不然不能正確回調(diào)弹灭。
4督暂、權(quán)限申請回調(diào):onRequestPermissionsResult
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted揪垄,do sth;
} else {
// permission denied,
Toast.makeText(getActivity(), "請授予權(quán)限", Toast.LENGTH_SHORT).show();
}
break;
}
}
權(quán)限申請的步驟大致就是以上幾步逻翁,如果申請成功就可以繼續(xù)愉(ku)快(bi)的敲你的代碼了饥努。