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,LiveDataeRoom.
- 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 WorkRequestpara solicitar que o trabalho seja realizado.
- Como adicionar restrições ao WorkRequestpara definir como e quando um worker deve ser executado.
- Como usar o WorkManagerpara 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 WorkRequestperió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.
- 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.
- Descompacte o código e abra o projeto no Android Studio.
- 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.
- 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. 
- No Android Studio, expanda todos os pacotes.
- Confira o pacote database. O pacote contém as entidades e o banco de dados local, que é implementado usandoRoom.
- Confira o pacote repository. O pacote contém a classeVideosRepository, que abstrai a camada de dados do restante do app.
- 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.
- Abra o arquivo build.gradle (Module:app)e adicione a dependênciaWorkManagerao 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"- 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- Workernesta tarefa.
- WorkRequest
 Essa classe representa uma solicitação para executar o worker em segundo plano. Use- WorkRequestpara 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- WorkRequestem uma tarefa posterior.
- WorkManager
 : essa classe agenda e executa a- WorkRequest. O- WorkManagerprograma solicitações de trabalho de modo a distribuir a carga nos recursos do sistema, respeitando as restrições especificadas. Você vai implementar o- WorkManagerem 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.
- No pacote devbyteviewer, crie um novo pacote chamadowork.
- No pacote work, crie uma classe Kotlin com o nomeRefreshDataWorker.
- Estenda a classe RefreshDataWorkerdaCoroutineWorker. TransmitacontexteWorkerParameterscomo parâmetros do construtor.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}- Para resolver o erro de classe abstrata, substitua o método doWork()na classeRefreshDataWorker.
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:
- Result.success(): o trabalho foi concluído com sucesso.
- Result.failure(): trabalho concluído com uma falha permanente.
- Result.retry(): o trabalho encontrou uma falha temporária e precisa ser repetido.
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.
- Na classe RefreshDataWorker, dentro dedoWork(), crie e instancie um objetoVideosDatabasee um objetoVideosRepository.
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)
   return Result.success()
}- Na classe RefreshDataWorker, dentro dedoWork(), acima da instruçãoreturn, chame o métodorefreshVideos()em um blocotry. 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.
- Confira a classe RefreshDataWorkercompleta 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.
- Na classe DevByteApplication, crie um método chamadosetupRecurringWork()para configurar o trabalho recorrente em segundo plano.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}- No método setupRecurringWork(), crie e inicialize uma solicitação de trabalho periódico para ser executada uma vez por dia usando o métodoPeriodicWorkRequestBuilder(). Transmita a classeRefreshDataWorkerque você criou na tarefa anterior. Transmita um intervalo de repetição de1com uma unidade de tempo deTimeUnit.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.
- 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"
}- Na classe DevByteApplication, no final do métodosetupRecurringWork(), programe o trabalho usando o métodoenqueueUniquePeriodicWork(). Transmita o enumKEEPpara o ExistingPeriodicWorkPolicy. TransmitarepeatingRequestcomo o parâmetroPeriodicWorkRequest.
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.
- No início da classe DevByteApplication, crie um objetoCoroutineScope. TransmitaDispatchers.Defaultcomo o parâmetro do construtor.
private val applicationScope = CoroutineScope(Dispatchers.Default)- Na classe DevByteApplication, adicione um novo método chamadodelayedInit()para iniciar uma corrotina.
private fun delayedInit() {
   applicationScope.launch {
   }
}- No método delayedInit(), chamesetupRecurringWork().
- Mova a inicialização do Timber do método onCreate()para o métododelayedInit().
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}- Na classe DevByteApplication, no final do métodoonCreate(), adicione uma chamada ao métododelayedInit().
override fun onCreate() {
   super.onCreate()
   delayedInit()
}- Abra o painel Logcat na parte de baixo da janela do Android Studio. Filtre por RefreshDataWorker.
- Execute o app. O WorkManagerprograma 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.
- Na classe DevByteApplication, dentro do métodosetupRecurringWork(), use um comentário para excluir a definição atual derepeatingRequest. Adicione uma nova solicitação de trabalho com um intervalo de repetição periódica de15minutos.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()- Abra o painel Logcat no Android Studio e filtre por RefreshDataWorker. Para limpar os registros anteriores, clique no ícone Limpar logcat . .
- Execute o app, e o WorkManagervai 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.)
- Na classe DevByteApplication, no início desetupRecurringWork(), defina umvaldo tipoConstraints. Use o métodoConstraints.Builder().
val constraints = Constraints.Builder()Para resolver o erro, importe androidx.work.Constraints.
- Use o método setRequiredNetworkType()para adicionar uma restrição de tipo de rede ao objetoconstraints. Use a enumeraçãoUNMETEREDpara que a solicitação de trabalho seja executada apenas quando o dispositivo estiver em uma rede ilimitada.
.setRequiredNetworkType(NetworkType.UNMETERED)- 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.
- Na classe DevByteApplication, dentro do métodosetupRecurringWork(), defina o objetoConstraintscomo a solicitação de trabalho periódico,repeatingRequest. Para definir as restrições, adicione o métodosetConstraints()acima da chamada do métodobuild().
       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.
- Desinstale o app do dispositivo ou emulador para cancelar as tarefas programadas anteriormente.
- Abra o painel Logcat no Android Studio. No painel Logcat, clique no ícone Limpar Logcat à esquerda para limpar os registros anteriores. Filtre por à esquerda para limpar os registros anteriores. Filtre porwork.
- 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.
- Execute o app e observe o painel Logcat. O WorkManagerprograma 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
- 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.
- Na classe DevByteApplication, dentro do métodosetupRecurringWork(), 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étodobuild()e use o métodosetRequiresBatteryNotLow().
.setRequiresBatteryNotLow(true)- 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étodosetRequiresCharging().
.setRequiresCharging(true)- 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étodosetRequiresDeviceIdle(). 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 SDKMe 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()- 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)
   }- Para remover a solicitação de trabalho programada anteriormente, desinstale o app DevBytes do dispositivo ou emulador.
- Execute o app, e o WorkManagervai 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.
- 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 WorkManagerfacilita 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 WorkManagersãoWorker,WorkRequesteWorkManager.
- A classe Workerrepresenta uma unidade de trabalho. Para implementar a tarefa em segundo plano, estenda a classeWorkere substitua o métododoWork().
- A classe WorkRequestrepresenta uma solicitação para realizar uma unidade de trabalho.WorkRequesté a classe de base para especificar parâmetros de trabalho que você programa noWorkManager.
- Há duas implementações concretas da classe WorkRequest:OneTimeWorkRequestpara tarefas únicas ePeriodicWorkRequestpara solicitações de trabalho periódicas.
- Ao definir a WorkRequest, você pode especificarConstraints, indicando quando oWorkerdeve 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 doConstraints.Builder. Por exemplo, para indicar que oWorkRequestnão deve ser executado se a bateria do dispositivo estiver fraca, use o métodosetRequiresBatteryNotLow()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 noWorkRequeste das otimizações do sistema. OWorkManagerfoi projetado para oferecer o melhor comportamento possível, considerando essas restrições.
Curso da Udacity:
Documentação do desenvolvedor Android:
- Como definir WorkRequests
- WorkManager
- Primeiros passos com o WorkManager
- Trabalho recorrente
- Guia para o processamento em segundo plano
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: 
Para acessar links de outros codelabs neste curso, consulte a página inicial dos codelabs de conceitos básicos do Kotlin para Android.