已声明定位权限仍提示'gps provider需ACCESS_FINE_LOCATION'报错原因是什么?
问题原因及解决方案
- 核心问题1:权限申请是异步操作,申请未完成就执行了位置获取逻辑
你当前的代码逻辑是:在onCreate中判断没有权限时调用requestLocationPermission()发起权限申请,但是Android的运行时权限申请是异步流程,调用申请方法后系统会弹出权限弹窗,此时主线程不会等待用户选择,会立刻执行后续的lm.getLastKnownLocation(LocationManager.GPS_PROVIDER)代码,此时权限还未获得,就会抛出缺少权限的报错。 - 核心问题2:权限校验的逻辑运算符使用错误
你当前的校验条件是(检查FINE权限未授予 && 检查COARSE权限未授予),只有两个权限都没授予的时候才会发起申请。如果用户之前授予过COARSE权限但是没授予FINE权限,就不会触发权限申请逻辑,而GPS_PROVIDER强制要求ACCESS_FINE_LOCATION权限,此时调用GPS相关接口就会报错。正确的逻辑应该把&&改为||,只要任意一个权限未授予就发起申请。 - 核心问题3:权限申请通过后没有重新触发位置获取逻辑
你在onRequestPermissionsResult中只处理了权限申请结果的提示,没有在用户同意权限后重新执行获取位置的代码,就算用户同意了权限,也不会再次尝试获取位置。 - 其他潜在问题
- 弹窗的按钮设置错误:你给AlertDialog连续调用了两次
setPositiveButton,第二个Cancel按钮应该调用setNegativeButton,否则Cancel的点击逻辑会覆盖第一个OK按钮的逻辑,用户点击OK也不会发起权限申请。 - 缺少空值校验:
getLastKnownLocation可能返回null,你直接调用location.getLatitude()会触发空指针崩溃。
- 弹窗的按钮设置错误:你给AlertDialog连续调用了两次
修复后的核心代码示例
首先将位置获取逻辑封装为公共方法:
// 封装获取位置的公共方法 private void tryGetLocation() { LocationManager lm = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestLocationPermission(); return; } Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null) { locationIn(location); } }
修改onCreate逻辑:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_basic); // 直接调用封装好的位置获取方法 tryGetLocation(); }
修改权限申请逻辑的运算符和弹窗按钮:
private void requestLocationPermission() { // 只要有一个权限需要申请就弹提示,将&&改为|| if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION) || ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_COARSE_LOCATION)){ new AlertDialog.Builder(this) .setTitle("Permission Needed") .setMessage("This permission needed to calculate prayers times") .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { ActivityCompat.requestPermissions(basicActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_PERMISSION_CODE); } }) // Cancel按钮改为setNegativeButton .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); } }).create().show(); }else { ActivityCompat.requestPermissions(basicActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_PERMISSION_CODE); } }
修改权限回调逻辑,授权通过后重新获取位置:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode==LOCATION_PERMISSION_CODE){ if (grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){ // 权限同意后重新尝试获取位置 tryGetLocation(); }else { Toast.makeText(this,"Location denied",Toast.LENGTH_SHORT).show(); } } }
内容的提问来源于stack exchange,提问作者user17010904
相关产品推荐
相关产品推荐

