Como fazer o encadeamento de trabalhos

O WorkManager permite que você crie e coloque em fila uma cadeira de trabalho que especifica várias tarefas dependentes e define a ordem em que elas serão executadas. Essa funcionalidade é particularmente útil quando você precisa executar várias tarefas em uma ordem específica.

Para criar uma cadeia de trabalhos, use WorkManager.beginWith(OneTimeWorkRequest) ou WorkManager.beginWith(List<OneTimeWorkRequest>), que retornam um instância de WorkContinuation.

Um WorkContinuation pode ser usado para adicionar instâncias de OneTimeWorkRequest dependentes usando then(OneTimeWorkRequest) ou then(List<OneTimeWorkRequest>)

Toda invocação de WorkContinuation.then(...) retorna uma novainstância de WorkContinuation. Se você adicionar uma List de instâncias de OneTimeWorkRequest, essas solicitações poderão ser executadas em paralelo.

Por fim, use o método WorkContinuation.enqueue() para enqueue() (enfileirar) sua cadeia de WorkContinuations.

Veja um exemplo. Neste exemplo, três jobs diferentes do worker estão configurados para serem executados (possivelmente em paralelo). Em seguida, os resultados desses workers serão unidos e transmitidos para um job de armazenamento em cache. Por fim, a saída desse job será transmitida para um worker de upload, que fará upload dos resultados para um servidor remoto.

Kotlin

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(listOf(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue()

Java

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(Arrays.asList(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue();

Fusões de entrada

Quando você encadeia instâncias de OneTimeWorkRequest, a saída das solicitações de trabalho pai é transmitida como entrada para os filhos. Portanto, no exemplo acima, as saídas de plantName1, plantName2 e plantName3 seriam transmitidas como entradas para a solicitação cache.

Para gerenciar entradas de várias solicitações de trabalho pai, o WorkManager usa InputMerger.

Há dois tipos diferentes de InputMerger fornecidos pelo WorkManager:

  • OverwritingInputMerger tenta adicionar todas as chaves de todas as entradas à saída. Em caso de conflitos, ela substitui todas as chaves definidas anteriormente.

  • ArrayCreatingInputMerger tenta mesclar as entradas, criando matrizes quando necessário.

Se você tiver um caso de uso mais específico, poderá criar sua própria subclasse InputMerger.

OverwritingInputMerger

OverwritingInputMerger é o método padrão de mesclagem. Se houver conflitos de chave na combinação, o valor mais recente de uma chave substituirá todas as versões anteriores nos dados de saída resultantes.

Por exemplo, se as entradas de fábrica tiverem uma chave correspondente aos respectivos nomes de variáveis ("plantName1", "plantName2" e "plantName3"), os dados transmitidos ao worker cache terão três pares de chave-valor.

Diagrama mostrando três jobs transmitindo saídas diferentes para o próximo job na cadeia. Como as três saídas têm chaves diferentes, o próximo job recebe três pares de chave-valor.

Se houver um conflito, o último worker a ser concluído "ganhará", e o valor dele será transmitido para cache.

Diagrama mostrando três jobs transmitindo saídas para o próximo job na cadeia. Nesse caso, dois desses jobs produzem saídas com a mesma chave. Como resultado, o próximo job recebe dois pares de chave-valor, com uma das saídas conflitantes descartada.

Como as solicitações de trabalho são executadas em paralelo, você não tem garantia da ordem em que elas são executadas. No exemplo acima, plantName1 pode conter um valor de "tulip" ou "elm", dependendo de qual valor foi gravado por último. Se você tiver um conflito de chaves e precisar preservar todos os dados de saída em uma mesclagem, ArrayCreatingInputMerger poderá ser uma opção melhor.

ArrayCreatingInputMerger

Para o exemplo acima, como queremos preservar as saídas de todos os workers de nome de fábrica, é necessário usar uma ArrayCreatingInputMerger.

Kotlin

val cache: OneTimeWorkRequest = OneTimeWorkRequestBuilder<PlantWorker>()
   .setInputMerger(ArrayCreatingInputMerger::class)
   .setConstraints(constraints)
   .build()

Java

OneTimeWorkRequest cache = new OneTimeWorkRequest.Builder(PlantWorker.class)
       .setInputMerger(ArrayCreatingInputMerger.class)
       .setConstraints(constraints)
       .build();

ArrayCreatingInputMerger pareia cada chave com uma matriz. Se cada uma das chaves for exclusiva, o resultado será uma série de matrizes de um elemento.

Diagrama mostrando três jobs transmitindo saídas diferentes para o próximo job na cadeia. O próximo job recebe três matrizes, uma para cada chave de saída. Cada matriz tem um único membro.

Se houver colisões de chave, todos os valores correspondentes serão agrupados em uma matriz.

Diagrama mostrando três jobs transmitindo saídas para o próximo job na cadeia. Nesse caso, dois desses jobs produzem saídas com a mesma chave. O próximo job recebe duas matrizes, uma para cada chave. Uma dessas matrizes tem dois membros, já que houve duas saídas com a chave.

Encadeamento e status de trabalho

As cadeias de OneTimeWorkRequest são executadas sequencialmente, desde que o trabalho seja concluído com sucesso (ou seja, desde que retornem um Result.success()). As solicitações de trabalho podem falhar ou ser canceladas durante a execução, o que afeta solicitações de trabalho dependentes.

Quando a primeira OneTimeWorkRequest é colocada em fila em uma cadeia de solicitações de trabalho, todas as solicitações de trabalho subsequentes são bloqueadas até que o trabalho da primeira solicitação seja concluído.

Diagrama mostrando uma cadeia de jobs. O primeiro job é colocado em fila. Todos os jobs seguintes são bloqueados até que o primeiro seja concluído.

Depois que a primeira solicitação de trabalho for colocada em fila e todas as restrições forem cumpridas, ela começará a ser executada. Se o trabalho for concluído na raiz OneTimeWorkRequest ou List<OneTimeWorkRequest> (ou seja, se ele retornar um Result.success()), o próximo conjunto de solicitações de trabalho dependentes será colocado na fila.

Diagrama mostrando uma cadeia de jobs. O primeiro trabalho foi concluído, e os dois sucessores imediatos estão na fila. Os jobs restantes são bloqueados, e os jobs anteriores são concluídos.

Desde que cada solicitação de trabalho seja concluída, esse mesmo padrão é propagado pelo restante da cadeia de solicitações até que todos os trabalhos da cadeia sejam concluídos. Embora esse seja o caso mais simples e geralmente o preferido, também é importante resolver os estados de erro.

Quando ocorre um erro no processamento da solicitação de trabalho por um worker, você pode repetir a solicitação de acordo com uma política de espera definida por você. A repetição de uma solicitação que faz parte de uma cadeia significa que apenas essa solicitação será repetida com os dados de entrada fornecidos. Nenhum trabalho em execução em paralelo será afetado.

Diagrama mostrando uma cadeia de jobs. Um dos jobs falhou, mas uma política de espera foi definida. Esse job será executado novamente depois do tempo necessário. Os próximos jobs da cadeia serão bloqueados até que o job com falha seja executado com sucesso.

Para ver mais informações sobre como definir estratégias personalizadas de novas tentativas, consulte Política de nova tentativa e espera.

Se a política de nova tentativa estiver indefinida ou esgotada, ou se você chegar a algum estado em que uma OneTimeWorkRequest retorna Result.failure(), essa solicitação de trabalho e todas as solicitações dependentes serão marcadas como FAILED..

Diagrama mostrando uma cadeia de jobs. Um job falhou e não pode ser repetido. Como resultado, todos os próximos jobs na cadeia também falharão.

A mesma lógica se aplica quando uma OneTimeWorkRequest é cancelada. Todas as solicitações de trabalho dependentes também serão marcadas como CANCELLED, e o trabalho delas não será executado.

Diagrama mostrando uma cadeia de jobs. Um job foi cancelado. Como resultado, todos os próximos jobs na cadeia também serão cancelados.

Se você anexar mais solicitações de trabalho a uma cadeia com falha ou com solicitações de trabalho canceladas, a solicitação recém-anexada também será marcada como FAILED ou CANCELLED, respectivamente. Se você quiser ampliar o trabalho de uma cadeia existente, consulte APPEND_OR_REPLACE em ExistingWorkPolicy.

Durante a criação de cadeias de solicitações de trabalho, as solicitações dependentes precisam definir políticas de novas tentativas para garantir que o trabalho seja sempre concluído em tempo hábil. Solicitações de trabalho com falha podem resultar em cadeias incompletas e/ou estados inesperados.

Para ver mais informações, consulte Como cancelar e interromper trabalhos.