O guia de primeiros passos
abordou como criar uma WorkRequest
simples e enfileirá-la.
Neste guia, você aprenderá a definir e personalizar objetos WorkRequest
para lidar com casos de uso comuns, por exemplo:
- Programar trabalhos únicos e recorrentes
- Definir restrições de trabalho, como exigir Wi-Fi ou carregamento
- Garantir um atraso mínimo na execução de trabalhos
- Definir estratégias de novas tentativas e espera
- Transmitir dados de entrada para os trabalhos
- Agrupar trabalhos relacionados usando tags
Geral
O trabalho é definido no WorkManager por meio de uma
WorkRequest
. Para
programar qualquer trabalho com o WorkManager, é preciso primeiro criar um
objeto WorkRequest
e depois colocá-lo em fila.
Kotlin
val myWorkRequest = ... WorkManager.getInstance(myContext).enqueue(myWorkRequest)
Java
WorkRequest myWorkRequest = ... WorkManager.getInstance(myContext).enqueue(myWorkRequest);
O objeto WorkRequest contém todas as informações necessárias para o WorkManager programar e executar seu trabalho. Isso inclui restrições que precisam ser atendidas para que seu trabalho seja executado, programação de informações como atrasos ou intervalos de repetição e configuração de novas tentativas, podendo incluir também dados de entrada caso seu trabalho dependa deles.
WorkRequest
é uma
classe básica abstrata. Há duas implementações derivadas dessa classe que
podem ser usadas para criar a solicitação,
OneTimeWorkRequest
e
PeriodicWorkRequest
.
Como os nomes indicam, OneTimeWorkRequest
é útil para programar um trabalho não
recorrente, enquanto PeriodicWorkRequest
é mais apropriada para programar
um trabalho que se repete em algum intervalo.
Programar trabalho único
Para trabalhos simples, que não requerem configuração adicional, use o método
estático
from
:
Kotlin
val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)
Java
WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);
Para trabalhos mais complexos, use um builder.
Kotlin
val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<MyWork>() // Additional configuration .build()
Java
WorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) // Additional configuration .build();
Programar trabalho periódico
Às vezes, seu app pode exigir que determinados trabalhos sejam executados periodicamente. Por exemplo, pode ser que você queira fazer backup dos seus dados, fazer o download de novos conteúdos no seu app ou fazer upload de registros para um servidor periodicamente.
Veja como usar a
PeriodicWorkRequest
para criar um objeto WorkRequest
que é executado periodicamente:
Kotlin
val saveRequest = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS) // Additional configuration .build()
Java
PeriodicWorkRequest saveRequest = new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS) // Constraints .build();
Neste exemplo, o trabalho é programado com um intervalo de uma hora.
O período é definido como o tempo mínimo entre repetições. O momento exato em que o worker será executado depende das restrições usadas no objeto WorkRequest e das otimizações feitas pelo sistema.
Intervalos de execução flexíveis
Se a natureza do trabalho torna necessário definir o tempo de execução, é possível configurar
a
PeriodicWorkRequest
para ser executada dentro de um período flexível em de cada período de intervalo, conforme mostrado
na Figura 1.
Figura 1. O diagrama mostra intervalos de repetição com o período flexível em que o trabalho pode ser executado.
Para definir o trabalho periódico com um período flexível, transmita um flexInterval
junto
ao repeatInterval
ao criar a PeriodicWorkRequest
. O período flexível
começa às repeatInterval - flexInterval
e dura até o fim do intervalo.
Veja a seguir um exemplo de trabalho periódico que pode ser executado nos últimos 15 minutos de cada período de uma hora.
Kotlin
val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>( 1, TimeUnit.HOURS, // repeatInterval (the period cycle) 15, TimeUnit.MINUTES) // flexInterval .build()
Java
WorkRequest saveRequest = new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS, 15, TimeUnit.MINUTES) .build();
O intervalo de repetição precisa ser maior ou igual a
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS
,
e o intervalo flexível
precisa ser maior ou igual a
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS
.
Efeito das restrições no trabalho periódico
Você pode aplicar restrições ao trabalho periódico. Por exemplo,
é possível adicionar uma restrição à solicitação de trabalho para que ele seja executado apenas
quando o dispositivo do usuário estiver sendo carregado. Nesse caso, mesmo que o intervalo de repetição
definido seja transmitido, a PeriodicWorkRequest
não será executada até que essa condição seja
atendida. Isso pode atrasar uma execução específica do seu trabalho ou até mesmo
ignorá-lo caso as condições não sejam atendidas no intervalo de execução.
Restrições de trabalho
As restrições garantem que o trabalho seja adiado até que as condições ideais sejam atendidas. As restrições a seguir estão disponíveis para o WorkManager.
NetworkType | Restringe o tipo de rede necessário para que o trabalho seja executado.
Por exemplo, Wi-Fi (UNMETERED ).
|
BatteryNotLow | Quando definida como "true", seu trabalho não será executado se o dispositivo estiver no modo de bateria fraca. |
RequiresCharging | Quando definida como "true", seu trabalho só será executado quando o dispositivo estiver sendo carregado. |
DeviceIdle | Quando definida como "true", o dispositivo do usuário precisará ficar inativo antes da execução do trabalho. Isso pode ser útil para executar operações em lote que podem ter um impacto negativo no desempenho de outros apps executados ativamente no dispositivo do usuário. |
StorageNotLow | Quando definida como "true", seu trabalho não será executado se o espaço de armazenamento do usuário no dispositivo estiver baixo demais. |
Para criar um conjunto de restrições e associá-lo a algum trabalho, crie uma
instância de Constraints
usando o Contraints.Builder()
e atribua-a ao
WorkRequest.Builder()
.
Por exemplo, o código a seguir cria uma solicitação de trabalho que só é executada quando o dispositivo do usuário está sendo carregado e está usando o Wi-Fi:
Kotlin
val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresCharging(true) .build() val myWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<MyWork>() .setConstraints(constraints) .build()
Java
Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresCharging(true) .build(); WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setConstraints(constraints) .build();
Quando várias restrições forem especificadas, o trabalho será executado somente quando todas elas forem atendidas.
Se uma restrição não seja atendida enquanto o trabalho estiver em execução, o WorkManager interromperá o worker. O trabalho será executado novamente quando todas as restrições forem atendidas.
Trabalho atrasado
Se o trabalho não tiver restrições ou se todas as restrições forem atendidas quando o trabalho for colocado em fila, o sistema poderá executá-lo imediatamente. Se você não quiser que o trabalho seja executado imediatamente, especifique um atraso inicial mínimo.
Veja um exemplo de como configurar seu trabalho para ser executado pelo menos 10 minutos depois de ser colocado em fila.
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>() .setInitialDelay(10, TimeUnit.MINUTES) .build()
Java
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setInitialDelay(10, TimeUnit.MINUTES) .build();
O exemplo ilustra como definir um atraso inicial para uma
OneTimeWorkRequest
, mas também é possível definir um atraso inicial para uma
PeriodicWorkRequest
. Nesse caso, somente a primeira execução do seu trabalho periódico
será atrasada.
Política de nova tentativa e espera
Se você precisa que o WorkManager tente realizar o trabalho novamente, pode retornar
Result.retry()
do worker. Seu trabalho é então reprogramado de acordo com um atraso de
espera e uma
política de espera.
O atraso de espera especifica o tempo mínimo que é necessário aguardar antes de tentar executar o trabalho novamente após a primeira tentativa. Esse valor não pode ser inferior a 10 segundos (ou MIN_BACKOFF_MILLIS).
A política de espera define como o atraso de espera aumentará ao longo do tempo para novas tentativas subsequentes. O WorkManager é compatível com duas políticas de espera,
LINEAR
eEXPONENTIAL
.
Cada solicitação de trabalho tem uma política de espera e um atraso de espera. A política padrão
é EXPONENTIAL
com um atraso de 10 segundos, mas você pode modificar essa configuração na
configuração da solicitação de trabalho.
Veja um exemplo de personalização do atraso e da política de espera.
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>() .setBackoffCriteria( BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) .build()
Java
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setBackoffCriteria( BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) .build();
Nesse exemplo, o atraso de espera mínimo é definido como o valor mínimo permitido,
10 segundos. Como a política é LINEAR
, o intervalo de repetição aumentará
aproximadamente 10 segundos a cada nova tentativa. Por exemplo, a primeira execução
terminada com Result.retry()
será tentada novamente após 10 segundos,
seguida por 20, 30, 40 e assim por diante se o trabalho continuar a retornar
Result.retry()
após tentativas subsequentes. Se a política de espera fosse definida como
EXPONENTIAL
, a sequência de duração da nova tentativa seria mais próxima de 20, 40, 80 e
assim por diante.
Incluir tag no trabalho
Cada solicitação de trabalho tem um identificador exclusivo que pode ser usado para identificá-la posteriormente e cancelar o trabalho ou observar o progresso dele.
Se você tem um grupo de trabalhos logicamente relacionados, também pode ser útil marcar esses itens de trabalho. A inclusão de tags permite que você opere com um grupo de solicitações de trabalho.
Por exemplo,
WorkManager.cancelAllWorkByTag(String)
cancela todas as solicitações de trabalho com uma tag específica, e
WorkManager.getWorkInfosByTag(String)
retorna uma lista dos objetos WorkInfo que podem ser usados para determinar o
estado de trabalho atual.
O código a seguir mostra como adicionar uma tag de "limpeza" ao seu trabalho:
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>() .addTag("cleanup") .build()
Java
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .addTag("cleanup") .build();
Por fim, várias tags podem ser adicionadas a uma única solicitação de trabalho. Internamente, essas tags são armazenadas como um conjunto de strings. A partir de uma solicitação de trabalho, você recupera o conjunto de tags por meio de WorkRequest.getTags().
Atribuir dados de entrada
Seu trabalho pode exigir dados de entrada para que seja realizado. Por exemplo, trabalhos que processam o upload de uma imagem podem exigir que o URI da imagem seja enviado por upload como entrada.
Os valores de entrada são armazenados como pares de chave-valor em um
objeto Data
e podem ser definidos na
solicitação de trabalho. O WorkManager entregará a entrada Data
para seu trabalho ao
executá-lo. A classe Worker
pode acessar os argumentos de entrada
chamando
Worker.getInputData()
.
O código abaixo mostra como criar uma instância de Worker
que requer dados de entrada e como enviá-la na solicitação de trabalho.
Kotlin
// Define the Worker requiring input class UploadWork(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) { override fun doWork(): Result { val imageUriInput = inputData.getString("IMAGE_URI") ?: return Result.failure() uploadFile(imageUriInput) return Result.success() } ... } // Create a WorkRequest for your Worker and sending it input val myUploadWork = OneTimeWorkRequestBuilder<UploadWork>() .setInputData(workDataOf( "IMAGE_URI" to "http://..." )) .build()
Java
// Define the Worker requiring input public class UploadWork extends Worker { public UploadWork(Context appContext, WorkerParameters workerParams) { super(appContext, workerParams); } @NonNull @Override public Result doWork() { String imageUriInput = getInputData().getString("IMAGE_URI"); if(imageUriInput == null) { return Result.failure(); } uploadFile(imageUriInput); return Result.success(); } ... } // Create a WorkRequest for your Worker and sending it input WorkRequest myUploadWork = new OneTimeWorkRequest.Builder(UploadWork.class) .setInputData( new Data.Builder() .putString("IMAGE_URI", "http://...") .build() ) .build();
Da mesma forma, a classe Data
pode ser usada para gerar um valor de retorno. Os dados de
entrada e saída são abordados com mais detalhes na seção Parâmetros de entrada e
valores retornados.
A seguir
Na página Estados e observação, você aprenderá mais sobre estados de trabalho e como monitorar o progresso do seu trabalho.