Depois de definir seu
Worker
e
sua WorkRequest
,
a última etapa é colocar o trabalho em fila. A maneira mais simples de fazer isso
é chamar o método enqueue()
do WorkManager, transmitindo a WorkRequest
que você
quer executar.
Kotlin
val myWork: WorkRequest = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork)
Java
WorkRequest myWork = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork);
Tenha cuidado para evitar duplicação ao colocar o trabalho em fila. Por exemplo, um app pode tentar fazer upload dos registros para um serviço de back-end a cada 24 horas. Se não tomar cuidado, você pode acabar colocando a mesma tarefa várias vezes na fila, mesmo que o job precise ser executado apenas uma vez. Para evitar esse problema, programe o trabalho como exclusivo.
Trabalho exclusivo
Trabalho exclusivo é um conceito eficiente que garante que você tenha apenas uma instância de trabalho com um nome específico por vez. Diferentemente dos IDs, os nomes exclusivos são legíveis por humanos e especificados pelo desenvolvedor em vez de gerados automaticamente pelo WorkManager. Também diferentemente das tags, os nomes exclusivos são associados apenas a uma instância de trabalho.
O trabalho exclusivo pode ser aplicado a trabalhos únicos e periódicos. Você pode criar uma sequência de trabalhos exclusivos chamando um destes métodos. O uso de um ou outro depende de você estar programando um trabalho recorrente ou único.
WorkManager.enqueueUniqueWork()
para trabalhos únicosWorkManager.enqueueUniquePeriodicWork()
para trabalhos periódicos
Esses dois métodos aceitam três argumentos:
- uniqueWorkName: uma
String
usada para identificar exclusivamente a solicitação de trabalho. - existingWorkPolicy: uma
enum
que informa ao WorkManager o que fazer se já existir uma cadeia de trabalho incompleta com o nome exclusivo. Para entender melhor, consulte a política de resolução de conflitos. - work: a
WorkRequest
a ser programada.
Com um trabalho exclusivo, podemos corrigir nosso problema de programação duplicada observado anteriormente.
Kotlin
val sendLogsWorkRequest = PeriodicWorkRequestBuilderS<endLogsWorker(>24, TimeUnit.HOURS) .setConstraints(Constraints.Builder() .setRequiresCharging(true) .build() ) .build() WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest )
Java
PeriodicWorkRequest sendLogsWorkRequest = new PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS) .setConstraints(new Constraints.Builder() .setRequiresCharging(true) .build() ) .build(); WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest);
Agora, se o código for executado enquanto um job sendLogs já estiver na fila, o job existente será mantido, e nenhum novo job será adicionado.
Sequências de trabalhos exclusivos também podem ser úteis caso você precise aumentar gradualmente uma longa cadeia de tarefas. Por exemplo, um app de edição de fotos pode permitir que os usuários desfaçam uma longa cadeia de ações. Cada uma dessas operações de desfazer uma ação pode demorar um pouco, mas elas precisam ser realizadas na ordem correta. Nesse caso, o app pode criar uma cadeia de "desfazer" e anexar cada operação de desfazer à cadeia, conforme necessário. Consulte Como encadear trabalhos para conferir os detalhes.
Política de resolução de conflitos
Ao agendar um trabalho exclusivo, você precisa informar ao WorkManager a ação que será realizada quando houver um conflito. Faça isso transmitindo um tipo enumerado ao processar o trabalho.
Para um trabalho único, você fornece uma
ExistingWorkPolicy
, que
oferece suporte a quatro opções para resolver o conflito.
REPLACE
(substituir) o trabalho existente pelo novo trabalho. Essa opção cancela o trabalho existente.KEEP
(manter) o trabalho existente e ignorar o novo trabalho.APPEND
(anexar) o novo trabalho ao final do trabalho existente. Essa política fará com que o novo trabalho seja encadeado ao trabalho existente. Ou seja, o novo será executado após o existente.
O trabalho existente se torna um pré-requisito do novo trabalho. Se o trabalho existente
se tornar CANCELLED
ou FAILED
, o novo trabalho também será CANCELLED
ou FAILED
.
Se você quiser que o novo trabalho seja executado independentemente do status do trabalho existente,
use APPEND_OR_REPLACE
.
APPEND_OR_REPLACE
funciona de forma semelhante aAPPEND
, mas não depende do pré-requisito de status do trabalho. Se o trabalho existente tiver o statusCANCELLED
ouFAILED
, o novo trabalho ainda será executado.
Para trabalhos periódicos, você fornece um
ExistingPeriodicWorkPolicy
,
que é compatível com duas opções, REPLACE
e KEEP
. Essas opções funcionam da mesma
forma que as contrapartes da ExistingWorkPolicy.
Como observar seu trabalho
A qualquer momento após colocar o trabalho em fila, você poderá consultar
o WorkManager pelo name
, id
ou por uma tag
associados a ele para verificar o status.
Kotlin
// by id workManager.getWorkInfoById(syncWorker.id) // ListenableFutureW<orkInfo<>/span> // by name workManager.getWorkInfosForUniqueWork("sync") // ListenableFutureL<istW<orkInfo<>/span> > // by tag workManager.getWorkInfosByTag("syncTag") // ListenableFutureL<istW<orkInfo<>/span> >
Java
// by id workManager.getWorkInfoById(syncWorker.id); // ListenableFutureW<orkInfo<>/span> // by name workManager.getWorkInfosForUniqueWork("sync"); // ListenableFutureL<istW<orkInfo<>/span> > // by tag workManager.getWorkInfosByTag("syncTag"); // ListenableFutureL<istW<orkInfo<>/span> >
A consulta retorna um
ListenableFuture
de um objeto WorkInfo
, que inclui o
id
do trabalho, as tags, o
State
atual e qualquer conjunto de
dados de saída via
Result.success(outputData)
.
Uma variante LiveData
de cada
método permite que você registre um listener para observar as mudanças das WorkInfo
. Por exemplo, se você quisesse exibir uma mensagem para o usuário quando
algum trabalho fosse concluído, poderia configurá-la assim:
Kotlin
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(viewLifecycleOwner) { workInfo - > if(workInfo?.state == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show() } }
Java
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(getViewLifecycleOwner(), workInfo - >{ if (workInfo.getState() != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show(); } });
Consultas de trabalho complexas
O WorkManager 2.4.0 e versões mais recentes são compatíveis com consultas complexas para jobs em fila
usando objetos WorkQuery
. O WorkQuery é compatível
com a consulta do trabalho por meio de uma combinação das tags, do estado e do nome exclusivo.
O exemplo a seguir mostra como encontrar todo o trabalho com a tag "syncTag",
que está no estado FAILED
ou CANCELLED
e tem o nome exclusivo
"preProcess" ou "sync".
Kotlin
val workQuery = WorkQuery.Builder .fromTags(listOf("syncTag")) .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .addUniqueWorkNames(listOf("preProcess", "sync") ) .build() val workInfos: ListenableFutureL<istW<orkInfo >>= workManager.getWorkInfos(workQuery)
Java
WorkQuery workQuery = WorkQuery.Builder .fromTags(Arrays.asList("syncTag")) .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .addUniqueWorkNames(Arrays.asList("preProcess", "sync") ) .build(); ListenableFutureL<istW<orkInfo >>workInfos = workManager.getWorkInfos(workQuery);
Cada componente (tag, estado ou nome) em uma WorkQuery
é adicionado por AND
aos
outros. Cada valor em um componente é incluído com OR
. Por exemplo: (name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
.
A WorkQuery
também funciona com o equivalente do LiveData,
getWorkInfosLiveData()
.
Como cancelar e interromper o trabalho
Se você não precisa mais de um trabalho que estava na fila, pode solicitar o
cancelamento. O trabalho pode ser cancelado por name
, id
ou por uma tag
associados a ele.
Kotlin
// by id workManager.cancelWorkById(syncWorker.id) // by name workManager.cancelUniqueWork("sync") // by tag workManager.cancelAllWorkByTag("syncTag")
Java
// by id workManager.cancelWorkById(syncWorker.id); // by name workManager.cancelUniqueWork("sync"); // by tag workManager.cancelAllWorkByTag("syncTag");
Em segundo plano, o WorkManager verifica o
State
do trabalho. Se o trabalho já estiver
concluído,
nada acontecerá. Caso contrário, o estado será mudado para
CANCELLED
, e o trabalho
não será executado no futuro. Todos os
jobs de WorkRequest
que forem dependentes
desse trabalho também
serão CANCELLED
.
Atualmente, o trabalho RUNNING
recebe uma chamada para
ListenableWorker.onStopped()
.
Modifique esse método para processar uma possível limpeza. Consulte o artigo Interromper um
worker em execução para mais informações.
Parar um worker em execução
Há alguns motivos diferentes para interromper a execução do Worker
no WorkManager:
- Você pediu explicitamente que ele fosse cancelado (chamando
WorkManager.cancelWorkById(UUID)
, por exemplo). - No caso de um trabalho exclusivo,
você colocou uma nova
WorkRequest
em fila com umaExistingWorkPolicy
deREPLACE
. AWorkRequest
antiga será imediatamente considerada cancelada. - As restrições do trabalho não são mais atendidas.
- O sistema instruiu o app a interromper o trabalho por algum motivo. Isso poderá acontecer se você exceder o prazo de execução de 10 minutos. O trabalho está programado para ser repetido mais tarde.
Nessas condições, o worker será interrompido.
Você precisa cancelar cooperativamente qualquer trabalho em andamento e liberar todos os recursos em uso pelo worker. Por exemplo, nesse momento é preciso fechar os identificadores abertos relacionados a bancos de dados e arquivos. Há dois mecanismos que você pode usar para saber quando o worker será parado.
Callback onStopped()
O WorkManager invoca
ListenableWorker.onStopped()
assim que seu worker é interrompido. Modifique esse método para fechar
todos os recursos em atividade.
Propriedade isStopped()
Chame o método
ListenableWorker.isStopped()
para verificar se o worker já foi interrompido. Se você estiver
realizando operações repetitivas ou de longa duração no worker, verifique
essa propriedade com frequência e use-a como um sinal para interromper o trabalho o mais
rápido possível.
Observação: o WorkManager ignora o
Result
definido por um worker
que tenha recebido o sinal onStop, porque ele já foi considerado
interrompido.