WorkManager 允许您在已排队后更新 WorkRequest
。这在经常更改约束或需要动态更新其工作者的较大应用中通常是必要的。从 WorkManager 2.8.0 版本开始,updateWork()
API 是执行此操作的方法。
updateWork()
方法允许您动态更改 WorkRequest
的某些方面,而无需手动取消并排队一个新的请求。这大大简化了开发过程。
避免取消工作
通常应避免取消现有的 WorkRequest 并排队一个新的请求。这样做会导致应用重复执行某些任务,并且可能需要编写大量额外的代码。
考虑以下取消 WorkRequest 可能导致困难的示例
- 后端请求:如果在计算要发送到服务器的有效负载时取消了
Worker
,则新的Worker
需要重新开始并重新计算可能代价高昂的有效负载。 - 调度:如果您取消了
PeriodicWorkRequest
,并且希望新的PeriodicWorkRequest
按相同的计划执行,则需要计算时间偏移量以确保新的执行时间与之前的任务请求对齐。
updateWork()
API 允许您更新工作请求的约束和其他参数,而无需取消并排队新的请求。
何时取消工作
在某些情况下,您应该直接取消 WorkRequest
,而不是调用 updateWork()
。当您希望更改已排队工作的基本性质时,您应该这样做。
何时更新工作
想象一个每天备份用户照片的图片应用。它已排队一个 PeriodicWorkRequest
来执行此操作。WorkRequest
具有要求设备充电并连接到 WiFi 的约束。
但是,用户每天只使用快速充电器为设备充电 20 分钟。在这种情况下,应用可能希望更新 WorkRequest
以放宽充电约束,以便即使设备未充满电也可以上传照片。
在这种情况下,您可以使用 updateWork()
方法更新工作请求的约束。
如何更新工作
updateWork()
方法提供了一种简单的方法来更新现有的 WorkRequest
,而无需取消并排队一个新的请求。
要使用更新已排队的工作,请按照以下步骤操作
- 获取已入队工作的现有 ID:获取要更新的 WorkRequest 的 ID。您可以使用任何
getWorkInfo
API 获取此 ID,或者在入队之前使用公共属性WorkRequest.id
手动持久化 WorkRequest 的 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()
。