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

权限授予后立即获取Android设备定位的问题排查

问题分析与解决方案

你的核心问题有两个:一是过时的onRequestPermissionsResult无法触发回调,二是getLocation的同步逻辑无法获取异步返回的定位结果,导致权限授予后立刻拿不到坐标,必须重启Fragment依赖缓存的lastKnownLocation。


1. 替换过时的权限请求方式(用Activity Result API)

onRequestPermissionsResult已被官方废弃,在Fragment配合导航组件时,旧方法常因生命周期问题无法触发回调。改用Activity Result API是官方推荐的可靠方案:

步骤1:初始化权限请求Launcher

在Fragment的onViewCreated中添加:

private val locationPermissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
    val isAllGranted = permissions.values.all { it }
    if (isAllGranted) {
        getLocation()
    } else {
        Toast.makeText(requireContext(), "需授予定位权限才能获取位置", Toast.LENGTH_SHORT).show()
    }
}

步骤2:修改requestPermissions函数

替换原来的权限请求逻辑:

fun requestPermissions() {
    locationPermissionLauncher.launch(
        arrayOf(
            android.Manifest.permission.ACCESS_FINE_LOCATION,
            android.Manifest.permission.ACCESS_COARSE_LOCATION
        )
    )
}

步骤3:删除过时的onRequestPermissionsResult

直接移除原来的onRequestPermissionsResult函数,无需保留。


2. 修复getLocation的异步逻辑

requestLocationUpdates是异步操作,你原来的代码在调用后立刻读取locationByGps/locationByNetwork,此时回调尚未触发,必然拿到空值。需要在定位回调中处理坐标更新,并完成后再执行导航:

步骤1:定义定位完成回调

private fun interface OnLocationReady {
    fun onReady(latitude: Double, longitude: Double)
}

步骤2:重写getLocation函数

fun getLocation(onLocationReady: OnLocationReady) {
    if (checkPermissions()) {
        if (isLocationEnabled()) {
            var hasReceivedLocation = false
            val locationListener = LocationListener { location ->
                if (!hasReceivedLocation) {
                    hasReceivedLocation = true
                    // 拿到定位后立刻移除更新,避免重复回调
                    locationManager.removeUpdates(locationListener)
                    // 通知定位完成
                    onLocationReady.onReady(location.latitude, location.longitude)
                }
            }

            // 注册GPS和网络定位回调,指定主线程处理
            locationManager.requestLocationUpdates(
                LocationManager.GPS_PROVIDER,
                0,
                0f,
                locationListener,
                Looper.getMainLooper()
            )
            locationManager.requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER,
                0,
                0f,
                locationListener,
                Looper.getMainLooper()
            )

            // 优先使用最后已知位置,避免等待过久
            val lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
                ?: locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
            lastKnownLocation?.let {
                if (!hasReceivedLocation) {
                    hasReceivedLocation = true
                    onLocationReady.onReady(it.latitude, it.longitude)
                }
            }
        } else {
            Toast.makeText(requireContext(), "请打开定位服务", Toast.LENGTH_LONG).show()
            startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
        }
    } else {
        requestPermissions()
    }
}

步骤3:修改按钮点击事件

等待定位完成后再更新模型并导航:

currentlocalisation.setOnClickListener {
    Toast.makeText(
        requireActivity(),
        "请将手机左右移动画八字形以加快定位",
        Toast.LENGTH_LONG
    ).show()
    getLocation(object : OnLocationReady {
        override fun onReady(latitude: Double, longitude: Double) {
            model.modifyCoordinatesLocation(longitude, latitude)
            findNavController().navigate(R.id.toPostel)
        }
    })
}

3. 优化:避免内存泄漏

在Fragment销毁时移除定位更新请求,防止内存泄漏:

override fun onDestroyView() {
    super.onDestroyView()
    // 注意:需在getLocation中持有locationListener的引用,才能在这里移除
    locationManager.removeUpdates(locationListener)
}

为什么原来的代码不生效?

  1. 过时的权限回调:onRequestPermissionsResult在导航组件管理的Fragment中,常会因Fragment被重新创建而无法触发回调,Activity Result API解决了这个问题。
  2. 同步逻辑错误:requestLocationUpdates的回调是异步触发的,你原来的代码在调用后立刻读取位置变量,此时回调还未执行,必然拿到空值;重启Fragment后能工作,是因为读取了缓存的lastKnownLocation,但权限刚授予时该缓存可能不存在。
  3. 提前导航:按钮点击后立刻执行导航,此时定位逻辑还未完成,模型中的坐标还是旧值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 16:48:14