Conceitos básicos do Kotlin para Android 09.2: WorkManager

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

Introdução

A maioria dos apps reais 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 nos dados. Essas operações precisam ser realizadas em segundo plano, fora da linha de execução de IU (linha de execução principal). As tarefas em segundo plano consomem recursos limitados do dispositivo, como a 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ê aprenderá a usar o WorkManager para programar 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 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 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 o trabalho a ser realizado.
  • Como adicionar restrições ao WorkRequest para definir como e quando um worker será executado.
  • Como usar o WorkManager para programar tarefas em segundo plano.

Atividades do laboratório

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

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

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

Para melhorar a experiência do usuário no app, faça uma pré-busca dos vídeos uma vez por dia. Isso garante que o usuário receba o conteúdo atualizado assim que abrir o app.

Nesta tarefa, você fará 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). Se preferir, faça o download do app inicial.

Nesta tarefa, você fará o download e executará o app inicial, além de examinar o código dele.

  1. Se você ainda não tem o app DevBytes, faça o download do código inicial 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 ou emulador de teste à Internet, se ainda não estiver conectado. Crie e execute o app. Ele busca a lista de vídeos DevByte da rede e os exibe.
  4. Toque em qualquer vídeo para abri-lo no app YouTube.

Etapa 2: analisar o código

O app inicial tem vários códigos que foram introduzidos no codelab anterior. O código inicial deste codelab tem módulos de rede, interface do usuário, cache off-line e repositório. Para se concentrar na programação da tarefa em segundo plano, use WorkManager.

  1. No Android Studio, expanda todos os pacotes.
  2. Conheça o pacote database. O pacote contém as entidades de banco de dados e o banco de dados local, que está implementado usando Room.
  3. Conheça o pacote repository. O pacote contém a classe VideosRepository que abstrai a camada de dados do restante do app.
  4. Explore 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. WorkManager é para trabalho em segundo plano que pode ser adiado e requer execução garantida:

  • Adiável significa que o trabalho não é necessário para ser executado imediatamente. Por exemplo, o envio de dados de análise ao servidor ou a sincronização do banco de dados em segundo plano é um trabalho que pode ser adiado.
  • Execução garantida significa que a tarefa será executada mesmo que o app seja fechado ou o dispositivo seja reiniciado.

Enquanto o WorkManager executa o trabalho em segundo plano, ele cuida dos problemas de compatibilidade e das práticas recomendadas de integridade da bateria e do sistema. WorkManager oferece compatibilidade com o nível 14 da API. 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.

WorkManager também permite definir critérios sobre quando a tarefa em segundo plano é executada. Por exemplo, talvez você queira que a tarefa seja executada somente quando o status da bateria, o status da rede ou o estado de carga atenderem a determinados critérios. Você aprenderá a definir restrições mais adiante neste codelab.

Neste codelab, você programa uma tarefa para fazer a pré-busca da playlist de vídeos DevBytes da rede uma vez por dia. Para programar esta 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 da solução será compilado como esperado. Se isso não acontecer, tente resolver o problema ou reverta 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 seu projeto e confira se não há erros de compilação.

Antes de adicionar o código ao projeto, conheça as seguintes classes na biblioteca WorkManager:

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

Etapa 1: criar um worker

Nesta tarefa, você adicionará um Worker para fazer a pré-busca da playlist de vídeos DevBytes em segundo plano.

  1. No pacote devbyteviewer, crie um novo pacote com o nome work.
  2. No pacote work, crie uma nova classe do 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 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 executa o trabalho de forma síncrona e precisa retornar um objeto ListenableWorker.Result. O sistema Android oferece um Worker no máximo 10 minutos para concluir a execução e retornar um objeto ListenableWorker.Result. Após esse período, o sistema forçará o fechamento de 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ê implementará o método doWork() para buscar a playlist de vídeos DevBytes da rede. É possível reutilizar os métodos existentes na classe VideosRepository para recuperar os dados da rede.

  1. Na classe RefreshDataWorker, em 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, no método doWork(), acima da instrução return, chame o método refreshVideos() dentro de um bloco try. Adicione um registro para monitorar 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. Veja 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()
   }
}

Uma 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 que só ocorrem uma vez. Uma tarefa única acontece apenas uma vez.
  • A classe PeriodicWorkRequest é destinada a trabalhos periódicos, tarefas que se repetem a cada intervalo.

As tarefas podem ser pontuais ou periódicas, portanto, escolha a classe de acordo. Para ver mais informações sobre como programar trabalhos recorrentes, consulte a documentação sobre trabalhos recorrentes.

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

Etapa 1: configurar trabalhos recorrentes

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 Application. A classe DevByteApplication é um bom lugar para programar a WorkManager.

  1. Na classe DevByteApplication, crie um método com o nome setupRecurringWork() para configurar o trabalho em segundo plano recorrente.
/**
* 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ódica 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 o WorkRequest, programe-o com WorkManager usando o método enqueueUniquePeriodicWork(). Esse método permite adicionar um PeriodicWorkRequest com o nome exclusivo à fila, em que apenas um PeriodicWorkRequest de um determinado nome 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á permitir que ela seja executada ou substituída com o novo trabalho, usando uma ExistingPeriodicWorkPolicy.

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

  1. Na classe RefreshDataWorker, adicione um objeto complementar no início da classe. Defina um nome de trabalho para identificar esse worker com exclusividade.
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 a enumeração KEEP para a 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 de trabalho.

  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 com o nome 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 para o método delayedInit().
override fun onCreate() {
   super.onCreate()
   delayedInit()
}
  1. Abra o painel Logcat na parte inferior da janela do Android Studio. Filtrar em RefreshDataWorker.
  2. Execute o app. O WorkManager programa seu trabalho recorrente imediatamente.

    No painel Logcat, observe os log statements que mostram que a solicitação de trabalho está programada e é executada corretamente.
D/RefreshDataWorker: Work request for sync is run
I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]

Como o registro WM-WorkerWrapper é exibido na biblioteca WorkManager, não é possível alterar essa mensagem de registro.

Etapa 3: (opcional) programar a WorkRequest para um intervalo mínimo

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

  1. Na classe DevByteApplication, no método setupRecurringWork(), comente a definição atual do repeatingRequest. Adicione uma nova solicitação de trabalho com um intervalo de repetição periódico 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 Clear logcat. .
  2. Execute o app, e o WorkManager programa 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 deverá ser executado.

    Observe que o intervalo pode ser inferior a 15 minutos e, às vezes, mais de 15 minutos. A duração exata está sujeita à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. No entanto, há um problema: você não especificou restrições. WorkManager programará o trabalho uma vez por dia, mesmo que o dispositivo esteja com pouca bateria, suspenso ou sem conexão de rede. Isso afetará a bateria e o desempenho do dispositivo e resultará em uma experiência insatisfatória para o usuário.

Na próxima tarefa, você vai adicionar uma restrição para resolver esse problema.

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

Ao definir o WorkRequest, você pode especificar restrições para quando o Worker será executado. Por exemplo, é possível especificar que o trabalho seja executado somente quando o dispositivo estiver ocioso ou apenas quando ele estiver conectado e conectado ao Wi-Fi. Também é possível especificar uma política de espera para repetir o trabalho. As restrições compatíveis são os métodos definidos 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ê criará um objeto Constraints e definirá uma restrição nele, uma restrição de tipo de rede. É mais fácil observar os registros com apenas uma restrição. Em uma etapa posterior, você adicionará outras restrições.

  1. Na classe DevByteApplication, no início do método 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 somente 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 como a solicitação de trabalho.

  1. Na classe DevByteApplication, no método setupRecurringWork(), defina o objeto Constraints como a solicitação de trabalho periódica, 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 ver os registros

Nesta etapa, você executa o app e percebe que a solicitação de trabalho restrito é executada em segundo plano em intervalos.

  1. Desinstale o app do dispositivo ou emulador para cancelar qualquer tarefa programada anteriormente.
  2. Abra o painel Logcat no Android Studio. No painel Logcat, limpe os registros anteriores clicando no ícone Clear logcat à esquerda. Filtrar em 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 precisa ser executada apenas em uma rede ilimitada. Como o Wi-Fi está desativado, o dispositivo não está conectado à rede, limitada ou ilimitada. Portanto, essa restrição não será atendida.
  4. Execute o app e veja o painel do Logcat. O WorkManager programa a tarefa em segundo plano imediatamente. Como a restrição de rede não foi atendida, a tarefa não foi executada.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
  1. Ative o Wi-Fi no dispositivo ou emulador e veja o painel Logcat. Agora a tarefa em segundo plano programada será executada aproximadamente a cada 15 minutos, contanto 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, você adicionará as seguintes restrições ao PeriodicWorkRequest:

  • A bateria não está fraca.
  • Carregando o dispositivo.
  • Dispositivo inativo, disponível apenas no nível de API 23 (Android M) e superior.

Implemente o seguinte na classe DevByteApplication.

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

Veja 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(), altere o intervalo de solicitação novamente para uma vez por dia.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .setConstraints(constraints)
       .build()

Veja a implementação completa do método setupRecurringWork(), com um registro para que você possa acompanhar quando a solicitação de trabalho periódica está 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 do emulador.
  2. Execute o app, e o WorkManager 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 ele não esteja em execução. Por esse motivo, você deve desinstalar o app do smartphone.

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

Projeto do Android Studio: DevBytesWorkManager.

  • 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 reais precisa executar tarefas em segundo plano de longa duração. Para programar uma tarefa em segundo plano de maneira otimizada e eficiente, use 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 modifique o método doWork().
  • A classe WorkRequest representa uma solicitação para executar uma unidade de trabalho. WorkRequest é a classe básica para especificar parâmetros para o trabalho programado em WorkManager.
  • Há duas implementações concretas da classe WorkRequest: OneTimeWorkRequest para tarefas únicas e PeriodicWorkRequest para solicitações de trabalho periódicas.
  • Ao definir o WorkRequest, você pode especificar Constraints indicando quando o Worker será executado. Isso inclui saber se o dispositivo está conectado, se ele está inativo ou se o Wi-Fi está conectado.
  • Para adicionar restrições à WorkRequest, use os métodos de conjunto listados na documentação de Constraints.Builder. Por exemplo, para indicar que o WorkRequest não pode ser executado se a bateria do dispositivo estiver baixa, use o método setRequiresBatteryNotLow() definido.
  • Depois de definir o WorkRequest, entregue a tarefa ao sistema Android. Para fazer isso, programe a tarefa usando um dos métodos enqueue WorkManager.
  • O tempo 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, de acordo com essas restrições.

Curso da Udacity:

Documentação do desenvolvedor Android:

Outro:

Esta seção lista as possíveis atividades para os alunos que estão trabalhando neste codelab como parte de um curso ministrado por um instrutor. Cabe ao instrutor fazer o seguinte:

  • Se necessário, atribua o dever de casa.
  • Informe aos alunos como enviar o dever de casa.
  • Atribua nota aos trabalhos de casa.

Os professores podem usar essas sugestões o quanto quiserem, e eles devem se sentir à vontade para passar o dever de casa como achar adequado.

Se você estiver fazendo este codelab por conta própria, use essas atividades 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 seguintes classes o WorkManager usa para programar a tarefa em segundo plano na API 23 e versões mais recentes?

▢ Apenas JobScheduler

BroadcastReceiver e AlarmManager

AlarmManager e JobScheduler

Scheduler e BroadcastReceiver

Pergunta 3

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

setConstraints()

addConstraints()

setConstraint()

addConstraintsToWorkRequest()

Vá para a próxima lição: 10.1 Estilos e temas

Para ver links de outros codelabs neste curso, consulte a página de destino dos codelabs do curso Conceitos básicos do Kotlin para Android.