WorkManager позволяет вам обновить WorkRequest
после того, как вы уже поставили его в очередь. Это часто необходимо в крупных приложениях, которые часто меняют ограничения или которым необходимо обновлять свои рабочие процессы на лету. Начиная с версии WorkManager 2.8.0, для этого используется API updateWork()
.
Метод updateWork()
позволяет вам изменять определенные аспекты WorkRequest
на лету, без необходимости вручную отменять и ставить в очередь новый запрос. Это значительно упрощает процесс разработки.
Избегайте отмены работы
Как правило, вам следует избегать отмены существующего WorkRequest и постановки нового в очередь. Это может привести к тому, что приложение будет повторять определенные задачи, и вам может потребоваться написать значительный объем дополнительного кода.
Рассмотрим следующие примеры того, где отмена WorkRequest может вызвать трудности:
- Внутренний запрос: если вы отменяете
Worker
, пока он вычисляет полезную нагрузку для отправки на сервер, новомуWorker
необходимо начать заново и пересчитать потенциально дорогостоящую полезную нагрузку. - Планирование: если вы отменяете
PeriodicWorkRequest
и хотите, чтобы новыйPeriodicWorkRequest
выполнялся по тому же расписанию, вам необходимо рассчитать смещение времени, чтобы гарантировать, что новое время выполнения соответствует предыдущему рабочему запросу.
API updateWork()
позволяет обновлять ограничения и другие параметры рабочего запроса без необходимости отмены и постановки нового запроса в очередь.
Когда отменить работу
В некоторых случаях вам следует напрямую отменить WorkRequest
, а не вызывать updateWork()
. Это то, что вам следует сделать, если вы хотите изменить фундаментальную природу работы, которую вы поставили в очередь.
Когда обновлять работу
Представьте себе фотоприложение, которое ежедневно выполняет резервное копирование фотографий пользователя. Для этого он поставил в PeriodicWorkRequest
. WorkRequest
имеет ограничения, требующие, чтобы устройство заряжалось и было подключено к Wi-Fi.
Однако пользователь заряжает свое устройство только 20 минут в день, используя быстрое зарядное устройство. В этом случае приложению может потребоваться обновить WorkRequest
, чтобы ослабить ограничение на зарядку, чтобы оно могло по-прежнему загружать фотографии, даже если устройство заряжено не полностью.
В этой ситуации вы можете использовать метод updateWork()
для обновления ограничений рабочего запроса.
Как обновить работу
Метод updateWork()
предоставляет простой способ обновления существующего WorkRequest
без необходимости его отмены и постановки нового в очередь.
Чтобы использовать работу в очереди обновлений, выполните следующие действия:
- Получить существующий идентификатор работы, поставленной в очередь . Получите идентификатор WorkRequest, который вы хотите обновить. Вы можете получить этот идентификатор с помощью любого из API-интерфейсов
getWorkInfo
или вручную сохранить идентификатор из исходного WorkRequest для последующего получения с помощью общедоступного свойстваWorkRequest.id
перед постановкой его в очередь. - Создайте новый WorkRequest : создайте новый
WorkRequest
и используйтеWorkRequest.Builder.setID()
чтобы установить его идентификатор, соответствующий идентификатору существующегоWorkRequest
. - Установить ограничения : используйте
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()
, чтобы получить экземплярWorkInfo
, соответствующий вашемуWorkRequest
.- Вы можете вызвать один из нескольких методов, возвращающих
WorkInfo
. Дополнительную информацию см. в справочнике по WorkManager .
- Вы можете вызвать один из нескольких методов, возвращающих
- getGeneration : вызовите
getGeneration()
для экземпляраWorkInfo
. Возвращенное значение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()
Политика обновления работы
Ранее рекомендуемым решением для обновления периодической работы было постановка запроса PeriodicWorkRequest
с политикой ExistingPeriodicWorkPolicy.REPLACE
. Если существовал ожидающий PeriodicWorkRequest
с тем же уникальным id
, новый рабочий запрос отменит и удалит его. Эта политика теперь устарела в пользу рабочего процесса, использующего ExistingPeriodicWorkPolicy.UPDATE
.
Например, при использовании enqueueUniquePeriodicWork
с PeriodicWorkRequest
вы можете инициализировать новый PeriodicWorkRequest
с помощью политики ExistingPeriodicWorkPolicy.UPDATE
. Если существует ожидающий запрос PeriodicWorkRequest
с тем же уникальным именем, WorkManager обновляет его в соответствии с новой спецификацией. Следуя этому рабочему процессу, нет необходимости использовать updateWork()
.