后台获取位置的Service禁用位置权限后崩溃问题求助
解决位置权限被禁用后Service崩溃的问题
这个问题我之前帮不少开发者排查过,从你给出的Logcat报错来看,原因非常明确:当用户在系统设置里禁用位置权限后,你的后台Service仍然在尝试执行位置相关操作,但此时应用已经没有权限了,直接抛出了SecurityException,而且这个异常发生在GoogleApiHandler的后台线程中,没有被捕获,最终导致应用崩溃。
下面是几个针对性的解决方案,按优先级排序:
1. 每次执行位置操作前强制检查权限状态
不管你之前是否已经获取过权限,每次发起位置请求或者在位置更新的循环/回调里,都要先检查权限是否还存在。用ContextCompat.checkSelfPermission()来做这件事非常方便:
// 检查是否拥有精细或粗略位置权限 boolean hasValidLocationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED; if (!hasValidLocationPermission) { // 权限已被禁用,立刻停止位置更新操作 stopLocationUpdates(); // 可选:根据业务需求,发送通知告知用户需要重新开启权限,或者直接停止Service return; } // 权限正常,继续执行位置相关逻辑
2. 捕获SecurityException异常做兜底处理
即使做了前置权限检查,也可能出现竞态条件(比如刚检查完权限,用户立刻在设置里禁用了它),所以一定要在调用位置API的代码块外加上try-catch:
try { // 这里是你的位置更新请求代码,比如FusedLocationProviderClient的requestLocationUpdates fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); } catch (SecurityException e) { // 捕获权限丢失的异常,做清理工作 Log.e("LocationService", "位置权限已丢失", e); stopLocationUpdates(); // 可以在这里给用户发送通知,提示权限被禁用了 }
3. 监听权限变化,主动响应状态更新
你可以在Service里注册一个广播接收器,监听权限状态的变化,这样能在权限被禁用/重新开启的第一时间做出响应:
private BroadcastReceiver permissionChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String changedPermission = intent.getStringExtra(PackageManager.EXTRA_PERMISSION_NAME); // 判断是否是位置权限发生了变化 if (Manifest.permission.ACCESS_FINE_LOCATION.equals(changedPermission) || Manifest.permission.ACCESS_COARSE_LOCATION.equals(changedPermission)) { // 重新检查权限并更新位置服务状态 checkPermissionAndManageLocationUpdates(); } } }; // 在Service的onCreate()方法里注册广播 @Override public void onCreate() { super.onCreate(); IntentFilter filter = new IntentFilter(PackageManager.ACTION_PERMISSION_CHANGED); registerReceiver(permissionChangeReceiver, filter); } // 在Service销毁时记得注销广播,避免内存泄漏 @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(permissionChangeReceiver); }
4. 优化后台Service的资源管理
当权限丢失后,你的后台Service其实已经无法完成核心功能了,这时候应该停止不必要的后台操作,避免浪费系统资源。比如调用stopSelf()来停止Service,或者切换到等待权限恢复的休眠状态,直到用户重新开启权限。
把这几个方案结合起来,就能彻底解决权限被禁用后应用崩溃的问题啦。
内容的提问来源于stack exchange,提问作者Suresh Kumar
相关产品推荐
相关产品推荐

