如何设置 LocationRequest 的 priority 为 PRIORITY_HIGH_ACCURACY?

解读

国内面试中,这道题表面考“一行代码”的写法,实则验证候选人是否真正踩过“定位”坑:

  1. 是否知道 FusedLocationProviderClient 这套 Google 官方推荐方案,而不是还在用已废弃的 LocationManager;
  2. 是否理解高精度定位背后意味着“GPS + 网络”双通道,从而带来功耗与权限上的连锁反应;
  3. 是否能在代码层面把 LocationRequest 构造出来,并正确声明权限、处理动态授权与后台定位合规(Android 10/11/12 三代政策差异)。
    如果候选人只回答“setPriority 就行”,面试官会追问功耗优化、后台限制、隐私合规、国产 ROM 兼容等,直到把“一行代码”扩展成“一套解决方案”。

知识点

  1. FusedLocationProviderClient:Google Play 服务里的融合定位,默认走 GMS 通道;国内无 GMS 机型需降级到 LocationManager 或第三方 SDK。
  2. LocationRequest 构建方式:
    • 旧版 new LocationRequest() 已废弃,必须用 LocationRequest.Builder。
    • setPriority(int) 参数为 int,但官方只接受 4 个枚举常量:PRIORITY_HIGH_ACCURACY、PRIORITY_BALANCED_POWER_ACCURACY、PRIORITY_LOW_POWER、PRIORITY_NO_POWER。
  3. 权限链路:
    • 前台定位:ACCESS_FINE_LOCATION(高精度必须)+ ACCESS_COARSE_LOCATION。
    • 后台定位:Android 10+ 需额外 ACCESS_BACKGROUND_LOCATION;Android 12+ 需同时在 Manifest 中声明 android:foregroundServiceType="location"。
  4. 动态授权:国产 ROM(小米、华为、OPPO)在系统设置里还有“始终允许”二次弹窗,需在代码里引导。
  5. 电量与系统限制:
    • 高功耗场景会被国产 ROM 杀后台,需启动前台服务并弹出通知。
    • Android 12 引入 LocationRequest.Builder.setIntervalMillis() 最小间隔限制为 30 min(后台),前台无硬性限制但仍受 Doze 模式影响。
  6. 合规:工信部 164 号文、App 违法违规收集使用个人信息行为认定方法,要求隐私政策里单独列出“精准定位”目的,并在首次调用前弹窗告知。

答案

// 1. 依赖:模块级 build.gradle 已引入
// implementation 'com.google.android.gms:play-services-location:21.0.1'

// 2. 权限:AndroidManifest.xml
// <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
// <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
// Android 10+ 后台定位再追加
// <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

// 3. 运行时授权通过后,构造 LocationRequest
val locationRequest = LocationRequest.Builder(
        Priority.PRIORITY_HIGH_ACCURACY,   // 高精度
        10_000L                            // 最快更新间隔 10 秒,可按业务调整
    ).apply {
        setMinUpdateIntervalMillis(5_000L) // 最小间隔 5 秒
        setWaitForAccurateLocation(true)   // 等首颗 GPS 锁定再回调,避免跳点
    }.build()

// 4. 请求定位
val client = LocationServices.getFusedLocationProviderClient(context)
val callback = object : LocationCallback() {
    override fun onLocationResult(result: LocationResult) {
        val location = result.lastLocation
        // TODO: 业务处理
    }
}
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
    client.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper())
}

说明:

  • 使用 LocationRequest.Builder 是 2021 年后官方唯一推荐方式;旧构造器已被标记 @Deprecated。
  • PRIORITY_HIGH_ACCURACY 内部会同时开启 GPS 与网络定位,首次冷启动可能耗时 3–10 s,国产 ROM 若关闭“高精度模式”开关会降级到网络定位,需在设置页引导用户。
  • 如果项目需要无 GMS 渠道(华为 AppGallery、国内 AOSP),需回退到 LocationManager,并通过 SettingsClient 检查系统设置是否开启定位,代码差异较大,面试时可主动提及“双方案兼容”思路。

拓展思考

  1. 功耗治理:
    高精准定位功耗≈200 mW,连续跑 1 h 可耗电 8–10%。面试可提“梯度策略”——前台 10 s 间隔,退后台升 60 s,灭屏后改用 PRIORITY_LOW_POWER 或被动监听,再叠加 SensorManager 计步判断用户静止时暂停请求。
  2. 国产 ROM 兼容:
    小米/华为有“后台定位权限”白名单,需引导用户手动加锁;OPPO/Vivo 的“高耗电保护”会强制杀服务,需弹出系统设置页。面试可展示自己封装的 RomUtils 判断厂商并跳转到对应设置页。
  3. 隐私合规脚本:
    可在 CI 阶段扫描 Manifest 与代码,若出现 ACCESS_BACKGROUND_LOCATION 但隐私政策文本未出现“后台定位”关键词,则自动阻断发版;这套脚本在字节、阿里内部已成标配。
  4. 替代方案:
    如果业务只是打卡、城市切换,可用 Android 12 引入的新 API——LocationManager.getCurrentLocation(),一次性拿点,系统自己管理功耗,无需维护前台服务。
  5. 车载与 Wear 差异:
    Automotive OS 对后台定位无限制,但要求 APK 必须 targetSdk≥32 且通过 Google Automotive 认证;Wear OS 则建议用 PRIORITY_BALANCED_POWER_ACCURACY,因电池容量更小,面试官若问 IoT 场景可顺势展开。