WorkManager 允许您在已将 WorkRequest
加入队列后对其进行更新。这在经常更改约束或需要动态更新其 worker 的大型应用中通常是必要的。从 WorkManager 2.8.0 版本开始,updateWork()
API 是执行此操作的方法。
updateWork()
方法允许您动态更改 WorkRequest
的某些方面,而无需手动取消并加入新的请求。这极大地简化了开发过程。
避免取消工作
通常应避免取消现有的 WorkRequest 并加入新的请求。这样做会导致应用重复某些任务,并且可能需要编写大量额外的代码。
考虑以下取消 WorkRequest 可能导致困难的示例
- 后端请求:如果您在
Worker
计算要发送到服务器的有效负载时取消它,则新的Worker
需要重新开始并重新计算可能很昂贵的有效负载。 - 调度:如果您取消
PeriodicWorkRequest
并希望新的PeriodicWorkRequest
按相同的计划执行,则需要计算时间偏移以确保新的执行时间与之前的 work request 对齐。
updateWork()
API 允许您更新 work request 的约束和其他参数,而无需取消并加入新的请求。
何时取消工作
在某些情况下,您应该直接取消 WorkRequest
,而不是调用 updateWork()
。当您希望更改已加入队列的工作的基本性质时,您应该这样做。
何时更新工作
假设有一个照片应用,它每天备份用户的照片。它已加入队列 PeriodicWorkRequest
来执行此操作。该 WorkRequest
具有要求设备正在充电并连接到 WiFi 的约束。
但是,用户每天只用快速充电器为设备充电 20 分钟。在这种情况下,应用可能希望更新 WorkRequest
以放宽充电约束,以便即使设备未充满电,它仍然可以上传照片。
在这种情况下,您可以使用 updateWork()
方法更新 work request 的约束。
如何更新工作
updateWork()
方法提供了一种简单的方法来更新现有的 WorkRequest
,而无需取消并加入新的请求。
要使用更新已加入队列的工作,请按照以下步骤操作
- 获取已加入队列工作的现有 ID:获取要更新的 WorkRequest 的 ID。您可以使用任何
getWorkInfo
API 或通过手动保存初始 WorkRequest 的 ID 以便稍后使用公共属性WorkRequest.id
在加入队列之前检索它来检索此 ID。 - 创建新的 WorkRequest:创建一个新的
WorkRequest
并使用WorkRequest.Builder.setID()
将其 ID 设置为与现有WorkRequest
的 ID 匹配。 - 设置约束:使用
WorkRequest.Builder.setConstraints()
向 WorkManager 传递新的约束。 - 调用 updateWork:将新的 WorkRequest 传递给
updateWork()
。
更新工作示例
以下是用 Kotlin 编写的代码片段示例,演示了如何使用 updateWork()
方法更改用于上传照片的 WorkRequest
的电池约束
suspend fun updatePhotoUploadWork() {
// Get instance of WorkManager.
val workManager = WorkManager.getInstance(context)
// Retrieve the work request ID. In this example, the work being updated is unique
// work so we can retrieve the ID using the unique work name.
val photoUploadWorkInfoList = workManager.getWorkInfosForUniqueWork(
PHOTO_UPLOAD_WORK_NAME
).await()
val existingWorkRequestId = photoUploadWorkInfoList.firstOrNull()?.id ?: return
// Update the constraints of the WorkRequest to not require a charging device.
val newConstraints = Constraints.Builder()
// Add other constraints as required here.
.setRequiresCharging(false)
.build()
// Create new WorkRequest from existing Worker, new constraints, and the id of the old WorkRequest.
val updatedWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(newConstraints)
.setId(existingWorkRequestId)
.build()
// Pass the new WorkRequest to updateWork().
workManager.updateWork(updatedWorkRequest)
}
处理结果
updateWork()
返回一个 ListenableFuture<UpdateResult>
。给定的 UpdateResult
可以具有多个值中的一个,这些值概述了 WorkManager 是否能够应用您的更改。它还指示何时能够应用更改。
有关更多信息,请参阅 updateWork()
和 UpdateResult
参考。
使用代数跟踪工作
每次更新 WorkRequest
时,其代数都会增加 1。这使您可以准确跟踪当前排队的 WorkRequest
。在观察、跟踪和测试工作请求时,代数为您提供了更多控制权。
要获取 WorkRequest
的代数,请按照以下步骤操作
- WorkInfo:调用
WorkManager.getWorkInfoById()
以检索与您的WorkRequest
对应的WorkInfo
实例。- 您可以调用返回
WorkInfo
的几种方法之一。有关更多信息,请参阅 WorkManager 参考。
- 您可以调用返回
- getGeneration:在
WorkInfo
实例上调用getGeneration()
。返回的Int
对应于WorkRequest
的代数。- 请注意,没有代数字段或属性,只有
WorkInfo.getGeneration()
方法。
- 请注意,没有代数字段或属性,只有
跟踪代数示例
以下是上面描述的工作流的示例实现,用于检索 WorkRequest
的代数。
// Get instance of WorkManager.
val workManager = WorkManager.getInstance(context)
// Retrieve WorkInfo instance.
val workInfo = workManager.getWorkInfoById(oldWorkRequestId)
// Call getGeneration to retrieve the generation.
val generation = workInfo.getGeneration()
更新工作的策略
以前,更新周期性工作的推荐解决方案是使用策略 ExistingPeriodicWorkPolicy.REPLACE
将 PeriodicWorkRequest
排队。如果存在具有相同唯一 id
的挂起 PeriodicWorkRequest
,则新的工作请求将取消并将其删除。此策略现已弃用,取而代之的是使用 ExistingPeriodicWorkPolicy.UPDATE
的工作流。
例如,当使用 enqueueUniquePeriodicWork
和 PeriodicWorkRequest
时,您可以使用 ExistingPeriodicWorkPolicy.UPDATE
策略初始化新的 PeriodicWorkRequest
。如果存在具有相同唯一名称的挂起 PeriodicWorkRequest
,WorkManager 会将其更新为新的规范。遵循此工作流,无需使用 updateWork()
。