1. 获取单次定位并显示经纬度

获取单次定位并显示经纬度 学习卡片

任务拆解:一次定位请求的完整链路

本例要完成的是一个最小可用的“单次定位”功能:点击按钮后请求一次高精度位置,把经纬度显示到界面上,同时把权限被拒绝、系统定位开关关闭这两种异常情况处理掉。核心 API 是 FusedLocationProviderClient 的 getCurrentLocation(),它比 getLastLocation() 更适合“单次定位”场景——后者可能返回过期缓存,前者会主动发起一次新的位置计算。

权限与定位开关的前置判断

Android 6.0 起定位权限属于运行时权限,必须在请求位置前检查并申请。同时,即使权限已授予,用户仍可能关闭系统定位开关,此时请求会失败或返回空结果。因此请求前需要做两层判断:

  • 权限层:检查 ACCESS_FINE_LOCATION 是否已授予;未授予则通过 ActivityResultLauncher 发起申请。
  • 开关层:通过 LocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) 判断定位服务是否开启;未开启则引导用户跳转到系统定位设置页。
权限被拒绝后不要反复弹窗,应给出明确提示并保留一个“重新申请”入口;定位开关关闭时,用 Settings.ACTION_LOCATION_SOURCE_SETTINGS 跳转设置页是最稳妥的做法。

请求参数与回调处理

调用 getCurrentLocation() 时需要传入 Priority 和 CancellationToken。单次高精度定位使用 Priority.PRIORITY_HIGH_ACCURACY,它会综合 GPS、Wi-Fi、基站给出尽可能精确的结果。返回的 Location 对象中,latitude 和 longitude 就是我们要显示的经纬度,accuracy 可用于判断结果可信度。

// 关键调用片段
fusedClient.getCurrentLocation(
    Priority.PRIORITY_HIGH_ACCURACY,
    cancellationToken
).addOnSuccessListener { location ->
    if (location != null) {
        val lat = location.latitude
        val lon = location.longitude
        val acc = location.accuracy
        binding.tvResult.text = "纬度: %.6f\n经度: %.6f\n精度: %.1f m"
            .format(lat, lon, acc)
    } else {
        binding.tvResult.text = "未获取到位置,请检查定位开关"
    }
}.addOnFailureListener { e ->
    binding.tvResult.text = "定位失败: ${e.message}"
}

异常分支与结果判读

整个流程有三个关键分支需要区分处理:权限被拒绝、定位开关关闭、请求成功但返回 null。前两者属于前置条件不满足,应在发起请求前拦截;后者通常发生在信号极差或系统刚重启时,应提示用户稍后重试。成功时除了显示经纬度,建议同时显示 accuracy,当精度值大于 100 米时提示“当前精度较低”。

单次定位请求链路与异常分支 用户点击 “获取位置”按钮 检查 FINE_LOCATION 权限是否已授予? 权限被拒绝 提示 + 重新申请入口 检查定位开关 GPS_PROVIDER 是否开启? 定位开关关闭 跳转系统定位设置页 发起请求 getCurrentLocation Priority HIGH_ACCURACY 结果回调处理 location != null → 显示经纬度 + accuracy location == null → 提示“未获取到位置” TextView 显示 纬度 / 经度 / 精度(米) 未授予 未开启 用户授权/开启后重试 结果判读参考 accuracy ≤ 30 m:精度良好,可直接使用 30 m < accuracy ≤ 100 m:精度一般 accuracy > 100 m:精度较低,建议提示用户 latitude / longitude:WGS-84 坐标系 显示格式:保留 6 位小数 ≈ 0.1 m 分辨率 注:accuracy 为系统估算值,非实测误差

验证与常见问题

现象可能原因处理方式
点击后无任何反应权限未申请或申请后未重新检查在 ActivityResultLauncher 回调中重新判断权限再发起请求
返回 null定位开关关闭或信号极差先检查 isProviderEnabled,再提示用户到开阔处重试
经纬度长时间不变误用了 getLastLocation 的缓存确认调用的是 getCurrentLocation
精度值很大室内或 GPS 信号弱提示用户到室外,或接受 Wi-Fi/基站定位的较低精度
不要在主线程中同步等待位置结果;getCurrentLocation 返回的是 Task,必须通过 addOnSuccessListener / addOnFailureListener 异步处理。另外,请求前应创建 CancellationToken,在页面销毁时取消,避免内存泄漏。