提问人:Kalpesh Doru 提问时间:11/10/2023 更新时间:11/10/2023 访问量:23
Android 中定期 WorkManager 的后台位置获取问题
Background Location Fetching Issue with Periodic WorkManager in Android
问:
我目前正在开发一个 Android 应用程序,我需要使用 Periodic WorkManager 在后台定期获取用户的位置。我已将 WorkRequest 设置为每 15 分钟触发一次,当应用程序位于前台时,它会成功检索用户的位置。
但是,当应用程序被终止或在后台时,我遇到了一个问题。尽管授予了所有必需的位置权限,但在这些情况下返回的位置为 null。
权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
接口和实现
interface LocationClient {
fun getLocationUpdates(context: Context, interval: Long): Flow<Location>
suspend fun getLocation(context: Context, interval: Long): Location
class LocationException(message: String) : Exception()
}
class LocationClientImpl @Inject constructor(
private val client: FusedLocationProviderClient
) : LocationClient {
@SuppressLint("MissingPermission")
override fun getLocationUpdates(context: Context, interval: Long): Flow<Location> {
return callbackFlow {
if (!context.hasLocationPermission()) {
throw LocationClient.LocationException("Missing location permission")
}
val locationManager =
context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
val isNetworkEnabled =
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
if (!isGpsEnabled && !isNetworkEnabled) {
throw LocationClient.LocationException(message = "GPS is disabled")
}
val request = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, interval)
.setWaitForAccurateLocation(false)
.build()
val locationCallback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
super.onLocationResult(result)
result.locations.lastOrNull()?.let { location ->
launch { send(location) }
}
}
}
client.requestLocationUpdates(
request,
locationCallback,
Looper.getMainLooper()
)
awaitClose {
client.removeLocationUpdates(locationCallback)
}
}
}
@SuppressLint("MissingPermission")
override suspend fun getLocation(context: Context, interval: Long): Location {
val request = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, interval)
.setWaitForAccurateLocation(false)
.build()
return suspendCancellableCoroutine { continuation ->
val locationCallback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
super.onLocationResult(result)
result.locations.lastOrNull()?.let { location ->
client.removeLocationUpdates(this)
continuation.resume(location)
}
}
override fun onLocationAvailability(availability: LocationAvailability) {
super.onLocationAvailability(availability)
if (!availability.isLocationAvailable) {
client.removeLocationUpdates(this)
continuation.resumeWithException(LocationClient.LocationException("Location not available"))
Log.e(this::class.java.name, "onLocationAvailability: ${availability.isLocationAvailable}", )
}
}
}
client.requestLocationUpdates(request, locationCallback, Looper.getMainLooper())
}
}
}
工人
@HiltWorker
class LocationWorker @AssistedInject constructor(
@Assisted var context: Context,
@Assisted parameters: WorkerParameters,
private val deviceRepo: DeviceRepo,
private val locationClient: LocationClient
) :
CoroutineWorker(context, parameters) {
private val TAG = "LocationWorker"
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
//deviceRepo.addDevice(context)
val result = locationClient.getLocation(context, 1000)
Log.d(TAG, "doWork: ${result.latitude}")
Result.success()
}
}
活动中的工作请求
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val workManager = WorkManager.getInstance(this@MainActivity)
val request: PeriodicWorkRequest =
PeriodicWorkRequestBuilder<LocationWorker>(
5,
TimeUnit.MINUTES
).setConstraints(constraints).build()
workManager.enqueueUniquePeriodicWork(
"reminder_notification_work",
ExistingPeriodicWorkPolicy.KEEP,
request
)
workManager.getWorkInfosForUniqueWorkLiveData("reminder_notification_work")
.observe(lifecycleOwner) { workInfo ->
workInfo.forEach {
workManagerState.value = it.state.toString()
}
}
答: 暂无答案
评论