Atualizar um trabalho que já está na fila

O WorkManager permite que você atualize um WorkRequest depois de o enfileirar. Isso geralmente é necessário em apps maiores que mudam restrições com frequência ou precisam atualizar os workers em tempo real. A partir do WorkManager versão 2.8.0, a API updateWork() é o meio para fazer isso.

O método updateWork() permite que você altere determinados aspectos de um WorkRequest imediatamente, sem precisar passar pelo processo de cancelamento e enfileiramento de um novo manualmente. Isso simplifica muito o processo de desenvolvimento.

Evite cancelar o trabalho

Em geral, evite cancelar um WorkRequest existente e colocar um novo na fila. Isso pode fazer com que o app repita algumas tarefas e exigir que você escreva uma quantidade significativa de código extra.

Considere os exemplos abaixo em que o cancelamento de uma WorkRequest pode causar dificuldades:

  • Solicitação de back-end: se você cancelar um Worker enquanto estiver computando um payload para enviar ao servidor, o novo Worker precisará ser reiniciado e recalcular o payload potencialmente caro.
  • Programação:se você cancelar um PeriodicWorkRequest e quiser que o novo PeriodicWorkRequest seja executado na mesma programação, será necessário calcular um ajuste de horário para garantir que o novo ambiente de execução esteja alinhado com a solicitação de trabalho anterior.

A API updateWork() permite atualizar as restrições de uma solicitação de trabalho e outros parâmetros sem o problema de cancelar e colocar uma nova solicitação na fila.

Quando cancelar um trabalho

Há casos em que é necessário cancelar diretamente um WorkRequest em vez de chamar updateWork(). Isso é o que você precisa fazer quando quiser alterar a natureza fundamental do trabalho que colocou em fila.

Quando atualizar o perfil de trabalho

Imagine um app de fotos que faz backup diário das fotos do usuário. Ela colocou um PeriodicWorkRequest na fila para fazer isso, já que o WorkRequest tem restrições que exigem que o dispositivo esteja carregando e conectado ao Wi-Fi.

No entanto, o usuário só carrega o dispositivo por 20 minutos por dia em um carregador rápido. Nesse caso, o app pode atualizar a WorkRequest para relaxar a restrição de carregamento e ainda poder fazer upload das fotos mesmo que o dispositivo não esteja totalmente carregado.

Nessa situação, use o método updateWork() para atualizar as restrições da solicitação de trabalho.

Como atualizar o perfil de trabalho

O método updateWork() oferece uma maneira simples de atualizar um WorkRequest já existente, sem precisar cancelar e colocar um novo em fila.

Para atualizar um trabalho na fila, siga estas etapas:

  1. Acessar o ID do trabalho na fila: acesse o ID da WorkRequest que você quer atualizar. É possível extrair esse ID com qualquer uma das APIs getWorkInfo ou mantendo o ID do WorkRequest inicial para ser recuperado depois com a propriedade pública WorkRequest.id antes de colocá-lo na fila.
  2. Criar nova WorkRequest: crie uma nova WorkRequest e use WorkRequest.Builder.setID() para definir o ID dela que corresponde ao da WorkRequest existente.
  3. Definir restrições: use WorkRequest.Builder.setConstraints() para transmitir novas restrições ao WorkManager.
  4. Chamar updateWork: transmita a nova WorkRequest para updateWork().

Exemplo de atualização de trabalho

Confira um exemplo de snippet de código em Kotlin que demonstra como usar o método updateWork() para mudar as restrições de bateria de um WorkRequest usado para fazer upload de fotos:

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)
}

Processar o resultado

updateWork() retorna um ListenableFuture<UpdateResult>. O UpdateResult fornecido pode ter um dos diversos valores que descrevem se o WorkManager conseguiu ou não aplicar as mudanças. Ele também indica quando foi possível aplicar a alteração.

Para mais informações, consulte a referência updateWork() e UpdateResult.

Monitore o trabalho com gerações

Cada vez que você atualiza um WorkRequest, a geração dele aumenta em um. Isso permite que você rastreie exatamente qual WorkRequest está na fila. As gerações oferecem mais controle ao observar, rastrear e testar solicitações de trabalho.

Para conseguir a geração de um WorkRequest, siga estas etapas:

  1. WorkInfo: chame WorkManager.getWorkInfoById() para extrair uma instância de WorkInfo correspondente à WorkRequest.
  2. getGeneration: chame getGeneration() na instância de WorkInfo. O Int retornado corresponde à geração do WorkRequest.
    • Não há um campo ou uma propriedade de geração, apenas o método WorkInfo.getGeneration().

Exemplo de geração de faixas

Confira abaixo um exemplo de implementação do fluxo de trabalho descrito acima para recuperar a geração de um 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()

Políticas para atualizar o trabalho

Anteriormente, a solução recomendada para atualizar o trabalho periódico era enfileirar uma PeriodicWorkRequest com a política ExistingPeriodicWorkPolicy.REPLACE. Se houvesse um PeriodicWorkRequest pendente com o mesmo id exclusivo, a nova solicitação de trabalho seria cancelado e excluído. Esta política foi descontinuada e substituída pelo fluxo de trabalho que usa ExistingPeriodicWorkPolicy.UPDATE.

Por exemplo, ao usar enqueueUniquePeriodicWork com um PeriodicWorkRequest, você pode inicializar o novo PeriodicWorkRequest com a política ExistingPeriodicWorkPolicy.UPDATE. Se houver um PeriodicWorkRequest pendente com o mesmo nome exclusivo, o WorkManager o atualizará para a nova especificação. Seguindo esse fluxo de trabalho, não é necessário usar updateWork().