WorkManager 允许您在已入队后更新 WorkRequest
。这对于经常更改限制或需要动态更新其 Worker 的大型应用来说通常是必要的。从 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
时,其“代次”都会递增一。这让您可以准确地跟踪当前入队的是哪个 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()
。