Обновить работу, которая уже поставлена ​​в очередь

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 без необходимости его отмены и постановки нового в очередь.

Чтобы использовать работу в очереди обновлений, выполните следующие действия:

  1. Получить существующий идентификатор работы, поставленной в очередь . Получите идентификатор WorkRequest, который вы хотите обновить. Вы можете получить этот идентификатор с помощью любого из API-интерфейсов getWorkInfo или вручную сохранить идентификатор из исходного WorkRequest для последующего получения с помощью общедоступного свойства WorkRequest.id перед постановкой его в очередь.
  2. Создайте новый WorkRequest : создайте новый WorkRequest и используйте WorkRequest.Builder.setID() чтобы установить его идентификатор, соответствующий идентификатору существующего WorkRequest .
  3. Установить ограничения : используйте WorkRequest.Builder.setConstraints() чтобы передать новые ограничения WorkManager.
  4. Вызов 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 , выполните следующие действия:

  1. WorkInfo : вызовите WorkManager.getWorkInfoById() , чтобы получить экземпляр WorkInfo , соответствующий вашему WorkRequest .
    • Вы можете вызвать один из нескольких методов, возвращающих WorkInfo . Дополнительную информацию см. в справочнике по WorkManager .
  2. 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() .