Conceitos básicos do Kotlin para Android 09.2: WorkManager

Este codelab faz parte do curso Conceitos básicos do Kotlin para Android. Você vai aproveitar mais este curso se fizer os codelabs em sequência. Todos os codelabs do curso estão listados na página inicial dos codelabs de princípios básicos do Kotlin para Android.

Introdução

A maioria dos apps do mundo real precisa executar tarefas em segundo plano de longa duração. Por exemplo, um app pode fazer upload de arquivos para um servidor, sincronizar dados de um servidor e salvá-los em um banco de dados Room, enviar registros para um servidor ou executar operações caras em dados. Essas operações precisam ser realizadas em segundo plano, fora da linha de execução da interface (linha de execução principal). As tarefas em segundo plano consomem os recursos limitados de um dispositivo, como a memória RAM e a bateria. Se isso não for feito corretamente, pode resultar em uma experiência ruim para o usuário.

Neste codelab, você vai aprender a usar o WorkManager para agendar uma tarefa em segundo plano de maneira otimizada e eficiente. Para saber mais sobre outras soluções disponíveis para processamento em segundo plano no Android, consulte o Guia para o processamento em segundo plano.

O que você já precisa saber

  • Como usar os Componentes da arquitetura do Android ViewModel, LiveData e Room.
  • Como fazer transformações em uma classe LiveData.
  • Como criar e iniciar uma corrotina.
  • Como usar adaptadores de vinculação na vinculação de dados.
  • Como carregar dados armazenados em cache usando um padrão de repositório.

O que você vai aprender

  • Como criar um Worker, que representa uma unidade de trabalho.
  • Como criar um WorkRequest para solicitar que o trabalho seja realizado.
  • Como adicionar restrições ao WorkRequest para definir como e quando um worker deve ser executado.
  • Como usar o WorkManager para programar tarefas em segundo plano.

Atividades deste laboratório

  • Crie um worker para executar uma tarefa em segundo plano e pré-buscar a playlist de vídeos do DevBytes na rede.
  • Programe a execução periódica do worker.
  • Adicione restrições à WorkRequest.
  • Programe um WorkRequest periódico que seja executado uma vez por dia.

Neste codelab, você vai trabalhar no app DevBytes que desenvolveu em um codelab anterior. Se você não tiver esse app, faça o download do código inicial para esta lição.

O app DevBytes mostra uma lista de vídeos do DevByte, que são tutoriais curtos feitos pela equipe de relações com desenvolvedores Android do Google. Os vídeos apresentam recursos para desenvolvedores e práticas recomendadas para desenvolvimento no Android.

Você melhora a experiência do usuário no app pré-buscando os vídeos uma vez por dia. Isso garante que o usuário receba conteúdo novo assim que abrir o app.

Nesta tarefa, você vai fazer o download e inspecionar o código inicial.

Etapa 1: fazer o download e executar o app inicial

Você pode continuar trabalhando no app DevBytes que criou no codelab anterior, se tiver um. Se preferir, faça o download do app inicial.

Nesta tarefa, você vai baixar e executar o app inicial e examinar o código inicial.

  1. Se você ainda não tiver o app DevBytes, faça o download do código inicial do DevBytes para este codelab no projeto DevBytesRepository do GitHub.
  2. Descompacte o código e abra o projeto no Android Studio.
  3. Conecte o dispositivo de teste ou emulador à Internet, se ele ainda não estiver conectado. Crie e execute o app. Ele vai buscar e mostrar a lista de vídeos do DevByte na rede.
  4. No app, toque em qualquer vídeo para abrir no app YouTube.

Etapa 2: explorar o código

O app inicial vem com muito código que foi apresentado no codelab anterior. O código inicial deste codelab tem módulos de rede, interface do usuário, cache off-line e repositório. Você pode se concentrar na programação da tarefa em segundo plano usando WorkManager.

  1. No Android Studio, expanda todos os pacotes.
  2. Confira o pacote database. O pacote contém as entidades e o banco de dados local, que é implementado usando Room.
  3. Confira o pacote repository. O pacote contém a classe VideosRepository, que abstrai a camada de dados do restante do app.
  4. Analise o restante do código inicial por conta própria e com a ajuda do codelab anterior.

O WorkManager é um dos componentes da arquitetura do Android e faz parte do Android Jetpack. O WorkManager é para trabalhos em segundo plano que podem ser adiados e exigem execução garantida:

  • Adiavel significa que o trabalho não precisa ser executado imediatamente. Por exemplo, o envio de dados analíticos para o servidor ou a sincronização do banco de dados em segundo plano são tarefas que podem ser adiadas.
  • A execução garantida significa que a tarefa será executada mesmo que o app seja encerrado ou o dispositivo seja reiniciado.

Enquanto o WorkManager executa o trabalho em segundo plano, ele cuida de problemas de compatibilidade e práticas recomendadas para a integridade da bateria e do sistema. O WorkManager oferece compatibilidade com versões anteriores até o nível 14 da API. O WorkManager escolhe uma maneira adequada de programar uma tarefa em segundo plano, dependendo do nível da API do dispositivo. Ele pode usar JobScheduler (na API 23 e versões mais recentes) ou uma combinação de AlarmManager e BroadcastReceiver.

O WorkManager também permite definir critérios para quando a tarefa em segundo plano é executada. Por exemplo, você pode querer que a tarefa seja executada somente quando o status da bateria, da rede ou da carga atender a determinados critérios. Você vai aprender a definir restrições mais adiante neste codelab.

Neste codelab, você vai programar uma tarefa para pré-buscar a playlist de vídeos do DevBytes na rede uma vez por dia. Para programar essa tarefa, use a biblioteca WorkManager.

  1. Abra o arquivo build.gradle (Module:app) e adicione a dependência WorkManager ao projeto.

    Se você usar a versão mais recente da biblioteca, o app de solução será compilado conforme o esperado. Se não for, tente resolver o problema ou volte para a versão da biblioteca mostrada abaixo.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"
  1. Sincronize o projeto e verifique se não há erros de compilação.

Antes de adicionar código ao projeto, familiarize-se com as seguintes classes na biblioteca WorkManager:

  • Worker
    : é nessa classe que você define o trabalho real (a tarefa) a ser executado em segundo plano. Você estende essa classe e substitui o método doWork(). O método doWork() é onde você coloca o código a ser executado em segundo plano, como sincronizar dados com o servidor ou processar imagens. Você vai implementar o Worker nesta tarefa.
  • WorkRequest
    Essa classe representa uma solicitação para executar o worker em segundo plano. Use WorkRequest para configurar como e quando executar a tarefa do worker, com a ajuda de Constraints, como dispositivo conectado ou Wi-Fi conectado. Você vai implementar o WorkRequest em uma tarefa posterior.
  • WorkManager
    : essa classe agenda e executa a WorkRequest. O WorkManager programa solicitações de trabalho de modo a distribuir a carga nos recursos do sistema, respeitando as restrições especificadas. Você vai implementar o WorkManager em uma tarefa posterior.

Etapa 1: criar um worker

Nesta tarefa, você vai adicionar um Worker para pré-buscar a playlist de vídeos do DevBytes em segundo plano.

  1. No pacote devbyteviewer, crie um novo pacote chamado work.
  2. No pacote work, crie uma classe Kotlin com o nome RefreshDataWorker.
  3. Estenda a classe RefreshDataWorker da CoroutineWorker. Transmita context e WorkerParameters como parâmetros do construtor.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}
  1. Para resolver o erro de classe abstrata, substitua o método doWork() na classe RefreshDataWorker.
override suspend fun doWork(): Result {
  return Result.success()
}

Uma função de suspensão é uma função que pode ser pausada e retomada mais tarde. Uma função de suspensão pode executar uma operação de longa duração e aguardar a conclusão dela sem bloquear a linha de execução principal.

Etapa 2: implementar doWork()

O método doWork() dentro da classe Worker é chamado em uma linha de execução em segundo plano. O método realiza o trabalho de forma síncrona e retorna um objeto ListenableWorker.Result. O sistema Android dá a um Worker um máximo de 10 minutos para concluir a execução e retornar um objeto ListenableWorker.Result. Depois que esse tempo expira, o sistema interrompe o Worker.

Para criar um objeto ListenableWorker.Result, chame um dos seguintes métodos estáticos para indicar o status de conclusão do trabalho em segundo plano:

Nesta tarefa, você vai implementar o método doWork() para buscar a playlist de vídeos do DevBytes na rede. É possível reutilizar os métodos atuais na classe VideosRepository para recuperar os dados da rede.

  1. Na classe RefreshDataWorker, dentro de doWork(), crie e instancie um objeto VideosDatabase e um objeto VideosRepository.
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)

   return Result.success()
}
  1. Na classe RefreshDataWorker, dentro de doWork(), acima da instrução return, chame o método refreshVideos() em um bloco try. Adicione um registro para acompanhar quando o worker é executado.
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
}

Para resolver o erro "Referência não resolvida", importe retrofit2.HttpException.

  1. Confira a classe RefreshDataWorker completa para sua referência:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {

   override suspend fun doWork(): Result {
       val database = getDatabase(applicationContext)
       val repository = VideosRepository(database)
       try {
           repository.refreshVideos()
       } catch (e: HttpException) {
           return Result.retry()
       }
       return Result.success()
   }
}

Um Worker define uma unidade de trabalho, e o WorkRequest define como e quando o trabalho será executado. Há duas implementações concretas da classe WorkRequest:

  • A classe OneTimeWorkRequest é destinada a tarefas únicas. Uma tarefa única acontece apenas uma vez.
  • A classe PeriodicWorkRequest é destinada a tarefas periódicas, ou seja, tarefas que se repetem a cada intervalo.

As tarefas podem ser pontuais ou periódicas. Escolha a classe de acordo com isso. Para mais informações sobre como programar trabalhos recorrentes, consulte a documentação de trabalho recorrente.

Nesta tarefa, você vai definir e programar um WorkRequest para executar o worker criado na tarefa anterior.

Etapa 1: configurar o trabalho recorrente

Em um app Android, a classe Application é a classe base que contém todos os outros componentes, como atividades e serviços. Quando o processo do aplicativo ou pacote é criado, a classe Application (ou qualquer subclasse de Application) é instanciada antes de qualquer outra classe.

Neste app de exemplo, a classe DevByteApplication é uma subclasse da classe Application. A classe DevByteApplication é um bom lugar para programar o WorkManager.

  1. Na classe DevByteApplication, crie um método chamado setupRecurringWork() para configurar o trabalho recorrente em segundo plano.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}
  1. No método setupRecurringWork(), crie e inicialize uma solicitação de trabalho periódico para ser executada uma vez por dia usando o método PeriodicWorkRequestBuilder(). Transmita a classe RefreshDataWorker que você criou na tarefa anterior. Transmita um intervalo de repetição de 1 com uma unidade de tempo de TimeUnit.DAYS.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build()

Para resolver o erro, importe java.util.concurrent.TimeUnit.

Etapa 2: programar uma WorkRequest com o WorkManager

Depois de definir seu WorkRequest, é possível programá-lo com WorkManager usando o método enqueueUniquePeriodicWork(). Esse método permite adicionar um PeriodicWorkRequest com nome exclusivo à fila, em que apenas um PeriodicWorkRequest de um nome específico pode estar ativo por vez.

Por exemplo, talvez você queira que apenas uma operação de sincronização esteja ativa. Se uma operação de sincronização estiver pendente, você poderá deixá-la em execução ou substituí-la pelo novo trabalho usando uma ExistingPeriodicWorkPolicy.

Para saber mais sobre como programar um WorkRequest, consulte a documentação do WorkManager.

  1. Na classe RefreshDataWorker, no início, adicione um objeto complementar. Defina um nome de trabalho para identificar exclusivamente esse trabalhador.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
  1. Na classe DevByteApplication, no final do método setupRecurringWork(), programe o trabalho usando o método enqueueUniquePeriodicWork(). Transmita o enum KEEP para o ExistingPeriodicWorkPolicy. Transmita repeatingRequest como o parâmetro PeriodicWorkRequest.
WorkManager.getInstance().enqueueUniquePeriodicWork(
       RefreshDataWorker.WORK_NAME,
       ExistingPeriodicWorkPolicy.KEEP,
       repeatingRequest)

Se houver um trabalho pendente (não concluído) com o mesmo nome, o parâmetro ExistingPeriodicWorkPolicy.KEEP fará com que o WorkManager mantenha o trabalho periódico anterior e descarte a nova solicitação.

  1. No início da classe DevByteApplication, crie um objeto CoroutineScope. Transmita Dispatchers.Default como o parâmetro do construtor.
private val applicationScope = CoroutineScope(Dispatchers.Default)
  1. Na classe DevByteApplication, adicione um novo método chamado delayedInit() para iniciar uma corrotina.
private fun delayedInit() {
   applicationScope.launch {
   }
}
  1. No método delayedInit(), chame setupRecurringWork().
  2. Mova a inicialização do Timber do método onCreate() para o método delayedInit().
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}
  1. Na classe DevByteApplication, no final do método onCreate(), adicione uma chamada ao método delayedInit().
override fun onCreate() {
   super.onCreate()
   delayedInit()
}
  1. Abra o painel Logcat na parte de baixo da janela do Android Studio. Filtre por RefreshDataWorker.
  2. Execute o app. O WorkManager programa seu trabalho recorrente imediatamente.

    No painel Logcat, observe as instruções de registro que mostram que a solicitação de trabalho foi programada e executada com sucesso.
D/RefreshDataWorker: Work request for sync is run
I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]

O registro WM-WorkerWrapper é mostrado na biblioteca WorkManager. Por isso, não é possível mudar essa mensagem de registro.

Etapa 3 (opcional): agendar o WorkRequest para um intervalo mínimo

Nesta etapa, você diminui o intervalo de tempo de um dia para 15 minutos. Isso é feito para que você possa ver os registros de uma solicitação de trabalho periódico em ação.

  1. Na classe DevByteApplication, dentro do método setupRecurringWork(), use um comentário para excluir a definição atual de repeatingRequest. Adicione uma nova solicitação de trabalho com um intervalo de repetição periódica de 15 minutos.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()
  1. Abra o painel Logcat no Android Studio e filtre por RefreshDataWorker. Para limpar os registros anteriores, clique no ícone Limpar logcat .
  2. Execute o app, e o WorkManager vai programar seu trabalho recorrente imediatamente. No painel Logcat, observe os registros. A solicitação de trabalho é executada uma vez a cada 15 minutos. Aguarde 15 minutos para ver outro conjunto de registros de solicitação de trabalho. Você pode deixar o app em execução ou fechá-lo. O gerenciador de trabalho ainda vai funcionar.

    O intervalo às vezes é menor que 15 minutos e às vezes é maior. O momento exato está sujeito às otimizações de bateria do SO.
12:44:40 D/RefreshDataWorker: Work request for sync is run
12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
12:59:24 D/RefreshDataWorker: Work request for sync is run
12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:15:03 D/RefreshDataWorker: Work request for sync is run
13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:29:22 D/RefreshDataWorker: Work request for sync is run
13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 
13:44:26 D/RefreshDataWorker: Work request for sync is run
13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
 

Parabéns! Você criou um worker e programou a solicitação de trabalho com WorkManager. Mas há um problema: você não especificou nenhuma restrição. WorkManager vai programar o trabalho uma vez por dia, mesmo que o dispositivo esteja com pouca bateria, em modo de espera ou sem conexão de rede. Isso afeta a bateria e o desempenho do dispositivo e pode resultar em uma experiência ruim para o usuário.

Na próxima tarefa, você vai resolver esse problema adicionando restrições.

Na tarefa anterior, você usou WorkManager para programar uma solicitação de trabalho. Nesta tarefa, você vai adicionar critérios para quando executar o trabalho.

Ao definir a WorkRequest, é possível especificar restrições para quando a Worker deve ser executada. Por exemplo, você pode especificar que o trabalho só será executado quando o dispositivo estiver inativo ou conectado à energia e ao Wi-Fi. Também é possível especificar uma política de espera para novas tentativas de trabalho. As restrições compatíveis são os métodos de definição em Constraints.Builder. Para saber mais, consulte Como definir suas solicitações de trabalho.

Etapa 1: adicionar um objeto Constraints e definir uma restrição

Nesta etapa, você vai criar um objeto Constraints e definir uma restrição nele, uma restrição de tipo de rede. É mais fácil notar os registros com apenas uma restrição. Em uma etapa posterior, você adiciona outras restrições.)

  1. Na classe DevByteApplication, no início de setupRecurringWork(), defina um val do tipo Constraints. Use o método Constraints.Builder().
val constraints = Constraints.Builder()

Para resolver o erro, importe androidx.work.Constraints.

  1. Use o método setRequiredNetworkType() para adicionar uma restrição de tipo de rede ao objeto constraints. Use a enumeração UNMETERED para que a solicitação de trabalho seja executada apenas quando o dispositivo estiver em uma rede ilimitada.
.setRequiredNetworkType(NetworkType.UNMETERED)
  1. Use o método build() para gerar as restrições do builder.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()

Agora você precisa definir o objeto Constraints recém-criado para a solicitação de trabalho.

  1. Na classe DevByteApplication, dentro do método setupRecurringWork(), defina o objeto Constraints como a solicitação de trabalho periódico, repeatingRequest. Para definir as restrições, adicione o método setConstraints() acima da chamada do método build().
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()

Etapa 2: executar o app e observar os registros

Nesta etapa, você vai executar o app e notar que a solicitação de trabalho restrita está sendo executada em segundo plano em intervalos.

  1. Desinstale o app do dispositivo ou emulador para cancelar as tarefas programadas anteriormente.
  2. Abra o painel Logcat no Android Studio. No painel Logcat, clique no ícone Limpar Logcat à esquerda para limpar os registros anteriores. Filtre por work.
  3. Desative o Wi-Fi no dispositivo ou emulador para ver como as restrições funcionam. O código atual define apenas uma restrição, indicando que a solicitação só deve ser executada em uma rede sem medição. Como o Wi-Fi está desativado, o dispositivo não está conectado à rede, seja ela limitada ou ilimitada. Portanto, essa restrição não será atendida.
  4. Execute o app e observe o painel Logcat. O WorkManager programa a tarefa em segundo plano imediatamente. Como a restrição de rede não é atendida, a tarefa não é executada.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
  1. Ative o Wi-Fi no dispositivo ou emulador e observe o painel Logcat. Agora, a tarefa em segundo plano programada é executada aproximadamente a cada 15 minutos, desde que a restrição de rede seja atendida.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
11:31:47 D/RefreshDataWorker: Work request for sync is run
11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
11:46:45 D/RefreshDataWorker: Work request for sync is run
11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:03:05 D/RefreshDataWorker: Work request for sync is run
12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:16:45 D/RefreshDataWorker: Work request for sync is run
12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:31:45 D/RefreshDataWorker: Work request for sync is run
12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
12:47:05 D/RefreshDataWorker: Work request for sync is run
12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 
13:01:45 D/RefreshDataWorker: Work request for sync is run
13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]

Etapa 3: adicionar mais restrições

Nesta etapa, adicione as seguintes restrições ao PeriodicWorkRequest:

  • A bateria não está fraca.
  • Carregamento do dispositivo.
  • Dispositivo inativo. Disponível apenas no nível 23 da API (Android M) e em versões mais recentes.

Implemente o seguinte na classe DevByteApplication.

  1. Na classe DevByteApplication, dentro do método setupRecurringWork(), indique que a solicitação de trabalho só deve ser executada se a bateria não estiver baixa. Adicione a restrição antes da chamada do método build() e use o método setRequiresBatteryNotLow().
.setRequiresBatteryNotLow(true)
  1. Atualize a solicitação de trabalho para que ela seja executada apenas quando o dispositivo estiver sendo carregado. Adicione a restrição antes da chamada do método build() e use o método setRequiresCharging().
.setRequiresCharging(true)
  1. Atualize a solicitação de trabalho para que ela seja executada apenas quando o dispositivo estiver inativo. Adicione a restrição antes da chamada do método build() e use o método setRequiresDeviceIdle(). Essa restrição executa a solicitação de trabalho apenas quando o usuário não está usando o dispositivo ativamente. Esse recurso só está disponível no Android 6.0 (Marshmallow) e versões mais recentes. Portanto, adicione uma condição para a versão do SDK M e versões mais recentes.
.apply {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       setRequiresDeviceIdle(true)
   }
}

Confira a definição completa do objeto constraints.

val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresBatteryNotLow(true)
       .setRequiresCharging(true)
       .apply {
           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               setRequiresDeviceIdle(true)
           }
       }
       .build()
  1. No método setupRecurringWork(), mude o intervalo de solicitação de volta para uma vez por dia.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .setConstraints(constraints)
       .build()

Esta é a implementação completa do método setupRecurringWork(), com um registro para que você possa acompanhar quando a solicitação de trabalho periódico é programada.

private fun setupRecurringWork() {

       val constraints = Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .setRequiresBatteryNotLow(true)
               .setRequiresCharging(true)
               .apply {
                   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                       setRequiresDeviceIdle(true)
                   }
               }
               .build()
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
               .setConstraints(constraints)
               .build()
       
       Timber.d("Periodic Work request for sync is scheduled")
       WorkManager.getInstance().enqueueUniquePeriodicWork(
               RefreshDataWorker.WORK_NAME,
               ExistingPeriodicWorkPolicy.KEEP,
               repeatingRequest)
   }
  1. Para remover a solicitação de trabalho programada anteriormente, desinstale o app DevBytes do dispositivo ou emulador.
  2. Execute o app, e o WorkManager vai programar imediatamente a solicitação de trabalho. A solicitação de trabalho é executada uma vez por dia, quando todas as restrições são atendidas.
  3. Essa solicitação de trabalho será executada em segundo plano enquanto o app estiver instalado, mesmo que não esteja em execução. Por isso, desinstale o app do smartphone.

Muito bem! Você implementou e programou uma solicitação de trabalho que não consome muita bateria para a pré-busca diária de vídeos no app DevBytes. O WorkManager vai programar e executar o trabalho, otimizando os recursos do sistema. Seus usuários e as baterias deles vão ficar muito felizes.

Projeto do Android Studio: DevBytesWorkManager (link em inglês).

  • A API WorkManager facilita a programação de tarefas adiáveis e assíncronas que precisam ser executadas de maneira confiável.
  • A maioria dos apps do mundo real precisa executar tarefas em segundo plano de longa duração. Para agendar uma tarefa em segundo plano de maneira otimizada e eficiente, use o WorkManager.
  • As principais classes na biblioteca WorkManager são Worker, WorkRequest e WorkManager.
  • A classe Worker representa uma unidade de trabalho. Para implementar a tarefa em segundo plano, estenda a classe Worker e substitua o método doWork().
  • A classe WorkRequest representa uma solicitação para realizar uma unidade de trabalho. WorkRequest é a classe de base para especificar parâmetros de trabalho que você programa no WorkManager.
  • Há duas implementações concretas da classe WorkRequest: OneTimeWorkRequest para tarefas únicas e PeriodicWorkRequest para solicitações de trabalho periódicas.
  • Ao definir a WorkRequest, você pode especificar Constraints, indicando quando o Worker deve ser executado. As restrições incluem se o dispositivo está conectado, se está inativo ou se o Wi-Fi está conectado.
  • Para adicionar restrições ao WorkRequest, use os métodos de definição listados na documentação do Constraints.Builder. Por exemplo, para indicar que o WorkRequest não deve ser executado se a bateria do dispositivo estiver fraca, use o método setRequiresBatteryNotLow() set.
  • Depois de definir o WorkRequest, entregue a tarefa ao sistema Android. Para fazer isso, programe a tarefa usando um dos métodos enqueueWorkManager.
  • O momento exato em que o Worker é executado depende das restrições usadas no WorkRequest e das otimizações do sistema. O WorkManager foi projetado para oferecer o melhor comportamento possível, considerando essas restrições.

Curso da Udacity:

Documentação do desenvolvedor Android:

Outro:

Esta seção lista as possíveis atividades de dever de casa para os alunos que estão fazendo este codelab como parte de um curso ministrado por um professor. Cabe ao professor fazer o seguinte:

  • Atribuir o dever de casa, se necessário.
  • Informar aos alunos como enviar deveres de casa.
  • Atribuir nota aos deveres de casa.

Os professores podem usar essas sugestões o quanto quiserem, podendo passar os exercícios que acharem mais apropriados como dever de casa.

Se você estiver seguindo este codelab por conta própria, sinta-se à vontade para usar esses deveres de casa para testar seu conhecimento.

Pergunta 1

Quais são as implementações concretas da classe WorkRequest?

OneTimeWorkPeriodicRequest

OneTimeWorkRequest e PeriodicWorkRequest

OneTimeWorkRequest e RecurringWorkRequest

OneTimeOffWorkRequest e RecurringWorkRequest

Pergunta 2

Qual das classes abaixo o WorkManager usa para agendar a tarefa em segundo plano na API 23 e em versões mais recentes?

▢ Somente JobScheduler

BroadcastReceiver e AlarmManager

AlarmManager e JobScheduler

Scheduler e BroadcastReceiver

Pergunta 3

Qual API você usa para adicionar restrições a uma WorkRequest?

setConstraints()

addConstraints()

setConstraint()

addConstraintsToWorkRequest()

Comece a próxima lição: 10.1 Estilos e temas

Para acessar links de outros codelabs neste curso, consulte a página inicial dos codelabs de conceitos básicos do Kotlin para Android.