多年来,我一直使用
FusedLocationClient.requestLocationUpdates
从设备获取位置数据。在过去的一个月(不确定具体时间),当应用程序处于后台时,此方法突然开始挂起。现在,它发生在所有设备上、所有以前运行的应用程序版本上。
一旦应用程序再次位于前台,例程将恢复,并且位置回调将被正确调用。
过去,如果我没有获得
ACCESS_BACKGROUND_LOCATION
授予,我也会有类似的行为。但是,在这种情况下,我确实拥有该许可。
我的位置代码大约每分钟执行一次。请记住,为了保持这篇文章的简单性,省略了很多行。如果我遗漏了任何重要的内容,我可以在这里添加。
Worker
当我第一次继承此代码库时,使用前台服务来完成此任务,该任务一直运行良好,直到Android 12
更新限制了前台服务:此更新阻止我们从后台启动前台服务,这是必要的,因为当我最初继承它时,该服务是如何构建的:它执行短期任务(收集位置),自行安排,然后在安排的时间再次执行,然后重复。如果不从后台启动服务,此流程将无法继续,因为应用程序可能会最小化。 在同一页面中,建议使用工作管理器而不是前台服务,这导致我从服务切换到工作器。无论如何,服务试图做的事情似乎更符合工人应该做的事情。直到上个月的某个时候,这似乎工作正常。
理论上,我可以将所有内容移回前台服务,然后修改服务以连续运行,而不是执行一项任务并一遍又一遍地调度自己,但如果可能的话,我试图避免这样的重大重构.
我的主要目标是让它继续执行短期任务并自行调度,就像它近 7 年以来一直在做的那样。但是,如果这种方法不再可行,我就硬着头皮重构它。
我尝试过的:
卸载并重新安装应用程序
private var fusedLocationClient: FusedLocationProviderClient? = null
private lateinit var locationCallback: LocationCallback
...
override fun doWork(): Result {
...
fusedLocationClient = LocationServices.getFusedLocationProviderClient(appContext)
locationCallback = object : LocationCallback() {
override fun onLocationResult(locRes: LocationResult) {
/* this is what's never getting reached when the app is in the background */
}
}
val locationRequestBuilder = LocationRequest.Builder(1000)
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
val locationBuilder = LocationSettingsRequest.Builder().addLocationRequest(locationRequestBuilder.build())
val settingsResult = LocationServices.getSettingsClient(appContext).checkLocationSettings(locationBuilder.build())
settingsResult.addOnCompleteListener { response ->
fusedLocationClient!!.requestLocationUpdates(locationRequestBuilder.build(), locationCallback, null)
}
...
}
ACCESS_FINE_LOCATION
已验证我拥有 ACCESS_BACKGROUND_LOCATION
中的所有位置权限确保省电模式未开启(已知如果省电模式开启,则会出现此行为)
AndroidManifest.xml
GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(appContext)
的使用以利用间隔,并将所有内容都放在前台服务中(而不是 Worker)。该服务在用户登录时启动,并持续运行,并在用户注销时停止。
这在大多数情况下似乎工作正常,但当用户在请求位置数据时选择“仅这一次”时,就会变得不可靠。不过,我会在一个单独的问题中问这个问题。