Android 12及以下版本FusedLocationProviderClient失效问题解决方案咨询
Android 12及以下版本FusedLocationProviderClient无法获取位置的解决方案
核心问题分析
你的代码仅依赖lastLocation获取位置,但该方法只能返回设备缓存的最近位置,如果设备没有缓存位置(比如刚开机、首次启动App、位置服务刚开启),就会返回null。另外,Android 12及以下的权限流程、位置服务检查逻辑也需要严格处理,否则会导致位置获取失败。
具体修复步骤
1. 确保权限配置与动态申请
- 在
AndroidManifest.xml中声明必要权限:
<!-- Android 12及以下 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 若需后台定位,需添加 --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
- 代码中动态申请权限,必须在获取位置前确认权限已授予:
private fun checkLocationPermission() { when { ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED -> { getLocation() } else -> { ActivityResultContracts.RequestMultiplePermissions().launch( arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION ) ) { permissions -> if (permissions.values.all { it }) { getLocation() } else { // 权限被拒绝,提示用户手动开启 } } } } }
2. 替换lastLocation为主动位置请求
不要仅依赖lastLocation,改用requestLocationUpdates主动获取实时位置:
private fun getLocation() { val locationRequest = LocationRequest.create().apply { priority = LocationRequest.PRIORITY_HIGH_ACCURACY interval = 10000 // 10秒更新一次,按需调整 fastestInterval = 5000 // 最快更新间隔 } val locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult) { super.onLocationResult(locationResult) locationResult.lastLocation?.let { location -> fusedLocationProviderClient?.removeLocationUpdates(this) processLocationData(location) } } } // 检查位置服务是否开启 val locationSettingsRequest = LocationSettingsRequest.Builder() .addLocationRequest(locationRequest) .build() LocationServices.getSettingsClient(this) .checkLocationSettings(locationSettingsRequest) .addOnSuccessListener { fusedLocationProviderClient?.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) } .addOnFailureListener { exception -> if (exception is ResolvableApiException) { // 弹出提示让用户开启位置服务 exception.startResolutionForResult(this, 1001) } } }
3. 优化Geocoder使用(避免主线程阻塞)
原代码中geocoder.getFromLocation是同步方法,会阻塞主线程,建议改用异步方法:
private fun processLocationData(location: Location) { val geocoder = Geocoder(this, Locale.getDefault()) geocoder.getFromLocationAsync(location.latitude, location.longitude, 1) { addresses -> addresses?.firstOrNull()?.let { address -> langitude = address.latitude.toString() longitude = address.longitude.toString() this.address = address.getAddressLine(0).toString() pin = address.postalCode ?: "" // 设备信息获取逻辑 val telephone = getSystemService(TELEPHONY_SERVICE) as TelephonyManager phone = telephone.line1Number ?: "" val dev_id = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) device_id = dev_id ?: "" brand = Build.BRAND model = Build.MODEL val str_dateTime = DateFormat.format("yyyy-MM-dd HH:mm:ss", Date()) alldataShowWaterMark = """ User Name: ${Constant.USER_FULL_NAME} Langitude: $langitude Longitude: $longitude Address: ${this.address} PinCode: $pin Phone No.: $phone Device Id: $device_id Brand Name: $brand Model No.: $model Data On Time: $str_dateTime """.trimIndent() } } }
4. 处理位置服务开启结果
在Activity中处理用户开启位置服务的结果:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == 1001 && resultCode == RESULT_OK) { getLocation() } }
关键注意事项
- 避免空指针:原代码中直接用
addresses!![0]容易触发异常,改用firstOrNull()安全处理。 - 后台定位权限:Android 10及以上若需后台定位,需额外申请
ACCESS_BACKGROUND_LOCATION。 - 位置服务检查:必须确保设备位置服务已开启,否则FusedLocationProviderClient无法工作。
内容的提问来源于stack exchange,提问作者Rahul Routh
相关产品推荐
相关产品推荐

