使用FusedLocationProviderClient时,「每次询问」权限下仅单次采集位置数据问题
「每次询问」权限模式下FusedLocationProviderClient位置采集问题的解决办法
问题根源
「每次询问」权限是Android的临时授权模式,授权仅对单次位置请求有效。FusedLocationProviderClient的持续更新请求不会自动触发二次授权弹窗,且系统权限检查会误返回PERMISSION_GRANTED,导致后续请求静默失败;另外,登出时未彻底清理客户端实例和缓存,导致复用了首次授权的旧位置数据。
具体修复方案
1. 每次采集前主动校验并触发授权
不要只依赖checkSelfPermission的结果,结合shouldShowRequestPermissionRationale判断是否需要再次请求授权(即使权限检查显示已授予):
fun startLocationCollection() { val hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED if (!hasPermission) { ActivityCompat.requestPermissions(...) return } // 针对「每次询问」模式,主动触发二次授权提示 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) { // 弹出自定义弹窗告知用户需要再次授权,然后重新发起权限请求 showPermissionPromptDialog { ActivityCompat.requestPermissions(...) } return } // 正式发起位置更新请求 fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()) }
2. 登出时彻底清理位置客户端状态
登出时不仅要移除回调,还要清除缓存并销毁客户端实例,避免复用旧状态:
fun onUserLogout() { fusedLocationProviderClient?.removeLocationUpdates(locationCallback) fusedLocationProviderClient?.flushLocations() // 清空位置缓存 fusedLocationProviderClient = null // 销毁实例 }
3. 监听权限变更事件
注册广播监听权限状态变化,当用户在系统设置中修改权限后,自动调整采集逻辑:
private val permissionChangeReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { intent?.takeIf { it.action == Intent.ACTION_PERMISSION_CHANGED }?.let { val changedPermission = it.getStringExtra(Intent.EXTRA_PERMISSION_NAME) if (changedPermission == Manifest.permission.ACCESS_FINE_LOCATION) { // 根据新权限状态重启或停止采集 adjustLocationCollection() } } } } // 在Service的onCreate中注册 registerReceiver(permissionChangeReceiver, IntentFilter(Intent.ACTION_PERMISSION_CHANGED)) // 在Service的onDestroy中注销 unregisterReceiver(permissionChangeReceiver)
4. 登录时重置位置缓存
登录成功后,先清空缓存再发起采集请求,确保获取最新位置:
fun onUserLoginSuccess() { fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this) fusedLocationProviderClient.flushLocations() startLocationCollection() }
关于是否为FusedLocationProviderClient的Bug
这不是官方Bug,属于「每次询问」权限模式的设计特性。官方文档中描述的“正常工作”针对的是持续授权场景,而临时授权模式需要开发者主动处理重复授权的逻辑,系统不会自动触发后续的授权弹窗。
内容的提问来源于stack exchange,提问作者Nelson
相关产品推荐
相关产品推荐

