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

Android定时Worker获取当前定位始终返回null的问题求助

问题:WorkManager中单次获取定位始终返回null的解决方法

问题背景

我有一个每10分钟运行一次的WorkManager Worker,每次启动需要获取当前经纬度,先后尝试了两种实现方式,但location始终返回null:

初始实现代码

private var fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(applicationContext)

override fun doWork(): Result {
    val priority = Priority.PRIORITY_HIGH_ACCURACY
    val cancellationTokenSource = CancellationTokenSource()

    fusedLocationClient.getCurrentLocation(priority, cancellationTokenSource.token)
        .addOnSuccessListener { location ->
            Log.e("Location", "location is found: $location")
            curLat = location.latitude
            curLong = location.longitude
        }
        .addOnFailureListener { exception ->
            Log.e("Location", "Oops location failed with exception: $exception")
        }
}

后续尝试(按建议使用CurrentLocationRequest)

val currentBuilder = CurrentLocationRequest.Builder().setDurationMillis(30000)
val currentLocationRequest = currentBuilder.build()
fusedLocationClient.getCurrentLocation(currentLocationRequest, null)
    .addOnSuccessListener { location ->
        Log.e("Location", "location is found: $location")
        curLat = location.latitude
        curLong = location.longitude
    }
    .addOnFailureListener { exception ->
        Log.e("Location", "Oops location failed with exception: $exception")
    }

已申请权限:android.permission.ACCESS_COARSE_LOCATION、android.permission.ACCESS_FINE_LOCATION和ACCESS_BACKGROUND_LOCATION,但仍无法获取有效定位。已知定位子系统未开启会返回null,但我仅需Worker启动时获取一次定位,不清楚如何正确"请求更新",且Worker没有onCreate方法,LocationRequest.create()已废弃,不知如何初始化定位服务。


解决方案

1. 先检查定位服务状态

在尝试获取定位前,必须确认设备的定位子系统已开启,否则无论如何都无法获取位置:

val locationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
val isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)

if (!isGpsEnabled && !isNetworkEnabled) {
    Log.e("Location", "定位服务未开启,无法获取位置")
    return Result.failure()
}

2. 结合缓存定位+单次主动更新

getCurrentLocation在无缓存定位且定位子系统未活跃时会返回null,因此建议先尝试获取缓存的最后位置,若缓存为空,再发起单次定位请求:

完整CoroutineWorker实现

class LocationWorker(appContext: Context, params: WorkerParameters) : CoroutineWorker(appContext, params) {
    private val fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(appContext)
    private var locationCallback: LocationCallback? = null

    override suspend fun doWork(): Result {
        // 检查定位服务状态
        val locationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
        val isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        if (!isGpsEnabled && !isNetworkEnabled) {
            Log.e("Location", "定位服务未开启")
            return Result.failure()
        }

        // 1. 尝试获取缓存的最后位置
        val lastLocation = runCatching { fusedLocationClient.lastLocation.await() }.getOrNull()
        lastLocation?.let {
            Log.e("Location", "从缓存获取定位: $it")
            curLat = it.latitude
            curLong = it.longitude
            return Result.success()
        }

        // 2. 缓存为空,发起单次定位请求
        return withContext(Dispatchers.IO) {
            val resultDeferred = CompletableDeferred<Result>()

            locationCallback = object : LocationCallback() {
                override fun onLocationResult(locationResult: LocationResult) {
                    locationResult.lastLocation?.let { location ->
                        Log.e("Location", "获取到最新定位: $location")
                        curLat = location.latitude
                        curLong = location.longitude
                        resultDeferred.complete(Result.success())
                    } ?: run {
                        Log.e("Location", "定位请求成功但未获取到位置数据")
                        resultDeferred.complete(Result.failure())
                    }
                    // 移除回调,避免内存泄漏
                    fusedLocationClient.removeLocationUpdates(this)
                }

                override fun onLocationAvailability(locationAvailability: LocationAvailability) {
                    if (!locationAvailability.isLocationAvailable) {
                        Log.e("Location", "当前定位不可用")
                        resultDeferred.complete(Result.failure())
                        fusedLocationClient.removeLocationUpdates(this)
                    }
                }
            }

            // 构建单次定位请求(替代废弃的LocationRequest.create())
            val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 0)
                .setMinUpdateIntervalMillis(0)
                .setMaxUpdateDelayMillis(0)
                .setNumUpdates(1) // 仅请求一次定位更新
                .build()

            try {
                fusedLocationClient.requestLocationUpdates(
                    locationRequest,
                    locationCallback,
                    Looper.getMainLooper()
                )
            } catch (e: SecurityException) {
                Log.e("Location", "定位权限异常: ${e.message}")
                resultDeferred.complete(Result.failure())
            }

            resultDeferred.await()
        }
    }

    override fun onStopped() {
        super.onStopped()
        // Worker停止时移除定位回调,防止内存泄漏
        locationCallback?.let { fusedLocationClient.removeLocationUpdates(it) }
    }

    companion object {
        var curLat = 0.0
        var curLong = 0.0
    }
}

3. 确保Worker在后台能正常执行

部分厂商的后台限制(如Doze模式)可能影响定位服务,建议给Worker设置setExpedited,让它在临时唤醒窗口中执行:

val periodicWorkRequest = PeriodicWorkRequestBuilder<LocationWorker>(10, TimeUnit.MINUTES)
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .build()

WorkManager.getInstance(applicationContext).enqueue(periodicWorkRequest)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:09:52