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

Android开发:FusedLocationProviderClient无法获取实时定位问题

Android FusedLocationProvider 单次定位失败排查修复方案

核心问题根因

  • 时序逻辑错误:fusedLocationClient.lastLocation返回null时,代码刚调用requestLocationUpdates就立刻访问mCurrentLocation赋值、移动相机,此时定位回调还未触发,lateinit修饰的mCurrentLocation未完成初始化,直接抛出异常。
  • 定位请求配置缺失:LocationRequest仅配置了优先级和定时间隔,未适配单次定位场景参数,系统定位服务冷启动阶段无法快速返回有效结果。
  • 对话框返回逻辑缺失:用户在定位服务开启弹窗点击确认后,未在onActivityResult回调中重新触发定位初始化流程,导致监听注册时机早于定位服务完全启动,无法收到位置回调。

分步修复方案

1. 修正定位取值时序

所有依赖定位结果的操作(经纬度赋值、相机移动)必须放到成功拿到有效位置对象之后执行,禁止在注册监听后立刻读取定位结果。
修正后的enableLocation方法参考代码:

@SuppressLint("MissingPermission")
private fun enableLocation(locationRequest: LocationRequest) {
    Log.e(TAG, "Inside Enable Location Start")
    map.isMyLocationEnabled = true

    // 统一处理拿到有效位置后的逻辑,避免重复代码
    fun handleLocationResult(location: Location) {
        mCurrentLocation = location
        currentLatLng = LatLng(location.latitude, location.longitude)
        val update = CameraUpdateFactory.newLatLngZoom(currentLatLng, 18f)
        map.animateCamera(update)
        Toast.makeText(requireContext(), "定位成功", Toast.LENGTH_SHORT).show()
    }

    locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult) {
            super.onLocationResult(locationResult)
            Log.e(TAG, "Inside on Location Result")
            locationResult.lastLocation?.let {
                handleLocationResult(it)
                // 拿到结果后移除监听,避免持续耗电
                fusedLocationClient.removeLocationUpdates(locationCallback)
            }
        }
    }

    fusedLocationClient.lastLocation.addOnCompleteListener { task ->
        if (task.isSuccessful && task.result != null) {
            // 缓存位置有效,直接使用
            handleLocationResult(task.result!!)
        } else {
            Log.e(TAG, "lastLocation为空,注册实时位置监听")
            // 缓存位置无效,注册监听等待实时定位结果,不要在这里读取mCurrentLocation
            fusedLocationClient.requestLocationUpdates(
                locationRequest,
                locationCallback,
                Looper.getMainLooper()
            )
        }
    }
}

2. 补全LocationRequest配置,适配单次定位场景

替换原有LocationRequest配置,增加单次定位相关参数,缩短首次定位等待时间:

val locationRequest = LocationRequest.create().apply {
    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
    interval = 10000L
    fastestInterval = 5000L // 最快定位回调间隔
    maxWaitTime = 30000L // 最长等待30秒超时
    numUpdates = 1 // 仅获取1次有效位置即自动停止监听
}

3. 补全定位开启弹窗的返回回调

在Fragment中重写onActivityResult方法,处理用户点击弹窗确认开启定位后的逻辑,重新触发定位检查:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_TURN_DEVICE_LOCATION_ON) {
        if (resultCode == Activity.RESULT_OK) {
            // 用户成功开启定位,重新检查定位设置并初始化
            checkDeviceLocationSettings(resolve = false)
        } else {
            // 用户拒绝开启定位,展示提示
            Snackbar.make(
                requireView().findViewById<CoordinatorLayout>(R.id.myCoordinatorLayout),
                R.string.location_required_error,
                Snackbar.LENGTH_INDEFINITE
            ).setAction(android.R.string.ok) {
                checkDeviceLocationSettings()
            }.show()
        }
    }
}

额外避坑项

  • 将lateinit var mCurrentLocation: Location修改为var mCurrentLocation: Location? = null,通过空安全访问避免时序问题导致的应用崩溃。
  • Android 12及以上版本需要同时申请ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION权限,仅申请精确定位权限可能导致定位返回失败。
  • 首次定位冷启动依赖设备GPS/网络状态,室内无GPS信号场景下建议开启网络定位辅助,否则可能出现长时间无回调的情况。
  • 定位监听注册前务必确认权限已授予,不要完全依赖@SuppressLint("MissingPermission")注解绕过检查。

内容的提问来源于stack exchange,提问作者awaqar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 18:31:01