You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 01:40:00