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() .