Agendador de trabalhos do Android

Este guia discute como agendar o trabalho em segundo plano usando a API do Agendador de Trabalho android, que está disponível em dispositivos Android que executam o Android 5.0 (nível de API 21) e superior.

Visão geral

Uma das melhores maneiras de manter um aplicativo Android responsivo ao usuário é garantir que o trabalho complexo ou de execução longa seja executado em segundo plano. No entanto, é importante que o trabalho em segundo plano não afete negativamente a experiência do usuário com o dispositivo.

Por exemplo, um trabalho em segundo plano pode sondar um site a cada três ou quatro minutos para consultar alterações em um conjunto de dados específico. Isso parece benigno, no entanto, teria um impacto desastroso na duração da bateria. O aplicativo ativará repetidamente o dispositivo, elevará a CPU para um estado de energia mais alto, ligará os rádios, fará as solicitações de rede e, em seguida, processará os resultados. Ele fica pior porque o dispositivo não desligará imediatamente e retornará ao estado ocioso de baixa potência. O trabalho em segundo plano mal agendado pode inadvertidamente manter o dispositivo em um estado com requisitos de energia desnecessários e excessivos. Essa atividade aparentemente inocente (sondar um site) tornará o dispositivo inutilizável em um período relativamente curto de tempo.

O Android fornece as SEGUINTEs APIs para ajudar na execução do trabalho em segundo plano, mas por si só elas não são suficientes para agendamento de trabalho inteligente.

  • Serviços de Intenção – os Serviços de Intenção são ótimos para executar o trabalho, no entanto, eles não fornecem nenhuma maneira de agendar o trabalho.
  • AlarmManager – essas APIs só permitem que o trabalho seja agendado, mas não fornecem nenhuma maneira de realmente executar o trabalho. Além disso, o AlarmManager só permite restrições baseadas em tempo, o que significa gerar um alarme em um determinado momento ou após um determinado período de tempo ter decorrido.
  • Receptores de Difusão – um aplicativo Android pode configurar receptores de transmissão para executar o trabalho em resposta a eventos ou Intenções em todo o sistema. No entanto, os receptores de transmissão não fornecem nenhum controle sobre quando o trabalho deve ser executado. Também as alterações no sistema operacional Android restringirão quando os receptores de transmissão funcionarem ou os tipos de trabalho aos quais eles podem responder.

Há dois recursos importantes para executar com eficiência o trabalho em segundo plano (às vezes chamado de trabalho em segundo plano ou trabalho):

  1. Agendamento inteligente do trabalho – é importante que, quando um aplicativo está fazendo um trabalho em segundo plano, ele o faça como um bom cidadão. O ideal é que o aplicativo não exija que um trabalho seja executado. Em vez disso, o aplicativo deve especificar condições que devem ser atendidas para quando o trabalho pode ser executado e, em seguida, agendar esse trabalho com o sistema operacional que executará o trabalho quando as condições forem atendidas. Isso permite que o Android execute o trabalho para garantir a máxima eficiência no dispositivo. Por exemplo, as solicitações de rede podem ser executadas em lote para serem executadas ao mesmo tempo para fazer uso máximo da sobrecarga envolvida com a rede.
  2. Encapsulando o trabalho – o código para executar o trabalho em segundo plano deve ser encapsulado em um componente discreto que pode ser executado independentemente da interface do usuário e será relativamente fácil de reagendar se o trabalho não for concluído por algum motivo.

O Agendador de Trabalhos do Android é uma estrutura interna do sistema operacional Android que fornece uma API fluente para simplificar o agendamento de trabalho em segundo plano. O Agendador de Trabalhos do Android consiste nos seguintes tipos:

  • O Android.App.Job.JobScheduler é um serviço do sistema usado para agendar, executar e, se necessário, cancelar trabalhos em nome de um aplicativo Android.
  • Uma Android.App.Job.JobService é uma classe abstrata que deve ser estendida com a lógica que executará o trabalho no thread main do aplicativo. Isso significa que o JobService é responsável por como o trabalho deve ser executado de forma assíncrona.
  • Um Android.App.Job.JobInfo objeto contém os critérios para orientar o Android quando o trabalho deve ser executado.

Para agendar o trabalho com o Agendador de Trabalho do Android, um aplicativo Xamarin.Android deve encapsular o código em uma classe que estende a JobService classe. JobService tem três métodos de ciclo de vida que podem ser chamados durante o tempo de vida do trabalho:

  • bool OnStartJob(parâmetros JobParameters) – esse método é chamado pelo para executar o JobScheduler trabalho e é executado no thread main do aplicativo. É responsabilidade do JobService executar o trabalho de forma assíncrona e retornar true se houver trabalho restante ou false se o trabalho for feito.

    Quando o JobScheduler chamar esse método, ele solicitará e reterá um wakelock do Android durante o trabalho. Quando o trabalho for concluído, é responsabilidade do JobService informar o JobScheduler fato por meio da chamada do método (descrito a JobFinished seguir).

  • JobFinished(Parâmetros JobParameters, bool needsReschedule) – Esse método deve ser chamado pelo JobService para informar JobScheduler que o trabalho foi feito. Se JobFinished não for chamado, o JobScheduler não removerá o wakelock, causando esvaziamento desnecessário da bateria.

  • bool OnStopJob(parâmetros JobParameters) – isso é chamado quando o trabalho é interrompido prematuramente pelo Android. Ele deverá retornar true se o trabalho deve ser reagendado com base nos critérios de repetição (discutidos abaixo com mais detalhes).

É possível especificar restrições ou gatilhos que controlarão quando um trabalho pode ou deve ser executado. Por exemplo, é possível restringir um trabalho para que ele só seja executado quando o dispositivo estiver carregando ou para iniciar um trabalho quando uma imagem for tirada.

Este guia discutirá detalhadamente como implementar uma JobService classe e agendá-la com o JobScheduler.

Requisitos

O Agendador de Trabalhos do Android requer o nível 21 da API do Android (Android 5.0) ou superior.

Usando o Agendador de Trabalhos do Android

Há três etapas para usar a API JobScheduler do Android:

  1. Implemente um tipo JobService para encapsular o trabalho.
  2. Use um JobInfo.Builder objeto para criar o JobInfo objeto que manterá os critérios para o JobScheduler executar o trabalho.
  3. Agende o trabalho usando JobScheduler.Schedule.

Implementar um JobService

Todo o trabalho executado pela biblioteca do Agendador de Trabalhos do Android deve ser feito em um tipo que estenda a Android.App.Job.JobService classe abstrata. A criação de um JobService é muito semelhante à criação de um Service com a estrutura do Android:

  1. Estenda a JobService classe .
  2. Decore a subclasse com o ServiceAttribute e defina o Name parâmetro como uma cadeia de caracteres composta pelo nome do pacote e pelo nome da classe (consulte o exemplo a seguir).
  3. Defina a Permission propriedade no ServiceAttribute para a cadeia de caracteres android.permission.BIND_JOB_SERVICE.
  4. Substitua o OnStartJob método , adicionando o código para executar o trabalho. O Android invocará esse método no thread main do aplicativo para executar o trabalho. Trabalho que levará mais tempo para que alguns milissegundos sejam executados em um thread para evitar o bloqueio do aplicativo.
  5. Quando o trabalho é feito, o JobService deve chamar o JobFinished método . Esse método é como JobService informa que o JobScheduler trabalho é feito. A falha na chamada JobFinished resultará na JobService colocação de demandas desnecessárias no dispositivo, reduzindo a duração da bateria.
  6. É uma boa ideia também substituir o OnStopJob método . Esse método é chamado pelo Android quando o trabalho está sendo desligado antes de ser concluído e oferece a JobService oportunidade de descartar corretamente todos os recursos. Esse método deverá retornar true se for necessário reagendar o trabalho ou false se não for desejável executar novamente o trabalho.

O código a seguir é um exemplo do mais simples JobService para um aplicativo, usando o TPL para executar de forma assíncrona algum trabalho:

[Service(Name = "com.xamarin.samples.downloadscheduler.DownloadJob", 
         Permission = "android.permission.BIND_JOB_SERVICE")]
public class DownloadJob : JobService
{
    public override bool OnStartJob(JobParameters jobParams)
    {            
        Task.Run(() =>
        {
            // Work is happening asynchronously
                      
            // Have to tell the JobScheduler the work is done. 
            JobFinished(jobParams, false);
        });

        // Return true because of the asynchronous work
        return true;  
    }

    public override bool OnStopJob(JobParameters jobParams)
    {
        // we don't want to reschedule the job if it is stopped or cancelled.
        return false; 
    }
}

Criando um JobInfo para agendar um trabalho

Os aplicativos Xamarin.Android não instanciam um JobService diretamente, em vez disso, passarão um JobInfo objeto para o JobScheduler. O JobScheduler criará uma instância do objeto solicitado JobService , agendando e executando o JobService de acordo com os metadados no JobInfo. Um JobInfo objeto deve conter as seguintes informações:

  • JobId – esse é um int valor usado para identificar um trabalho para o JobScheduler. Reutilizá-lo atualizará todos os trabalhos existentes. O valor deve ser exclusivo para o aplicativo.
  • JobService – esse parâmetro é um ComponentName que identifica explicitamente o tipo que o JobScheduler deve usar para executar um trabalho.

Este método de extensão demonstra como criar um com um JobInfo.Builder Android Context, como uma Atividade:

public static class JobSchedulerHelpers
{
    public static JobInfo.Builder CreateJobBuilderUsingJobId<T>(this Context context, int jobId) where T:JobService
    {
        var javaClass = Java.Lang.Class.FromType(typeof(T));
        var componentName = new ComponentName(context, javaClass);
        return new JobInfo.Builder(jobId, componentName);
    }
}

// Sample usage - creates a JobBuilder for a DownloadJob and sets the Job ID to 1.
var jobBuilder = this.CreateJobBuilderUsingJobId<DownloadJob>(1);

var jobInfo = jobBuilder.Build();  // creates a JobInfo object.

Um recurso avançado do Agendador de Trabalhos do Android é a capacidade de controlar quando um trabalho é executado ou em quais condições um trabalho pode ser executado. A tabela a seguir descreve alguns dos métodos em JobInfo.Builder que permitem que um aplicativo influencie quando um trabalho pode ser executado:

Método Descrição
SetMinimumLatency Especifica que um atraso (em milissegundos) que deve ser observado antes de um trabalho ser executado.
SetOverridingDeadline Declara que o trabalho deve ser executado antes dessa vez (em milissegundos) ter decorrido.
SetRequiredNetworkType Especifica os requisitos de rede para um trabalho.
SetRequiresBatteryNotLow O trabalho só poderá ser executado quando o dispositivo não estiver exibindo um aviso de "bateria baixa" para o usuário.
SetRequiresCharging O trabalho só pode ser executado quando a bateria está carregando.
SetDeviceIdle O trabalho será executado quando o dispositivo estiver ocupado.
SetPeriodic Especifica que o trabalho deve ser executado regularmente.
SetPersisted O trabalho deve perisistá-lo entre reinicializações de dispositivo.

O SetBackoffCriteria fornece algumas diretrizes sobre quanto tempo o JobScheduler deve esperar antes de tentar executar um trabalho novamente. Há duas partes para os critérios de retirada: um atraso em milissegundos (valor padrão de 30 segundos) e um tipo de retirada que deve ser usado (às vezes chamado de política de retirada ou política de repetição). As duas políticas são encapsuladas na Android.App.Job.BackoffPolicy enumeração :

  • BackoffPolicy.Exponential – Uma política de retirada exponencial aumentará o valor de retirada inicial exponencialmente após cada falha. Na primeira vez que um trabalho falhar, a biblioteca aguardará o intervalo inicial especificado antes de reagendar o trabalho – exemplo, 30 segundos. Na segunda vez que o trabalho falhar, a biblioteca aguardará pelo menos 60 segundos antes de tentar executar o trabalho. Após a terceira tentativa com falha, a biblioteca aguardará 120 segundos e assim por diante. Esse é o valor padrão.
  • BackoffPolicy.Linear – Essa estratégia é uma retirada linear que o trabalho deve ser reagendado para ser executado em intervalos definidos (até que seja bem-sucedido). A retirada linear é mais adequada para o trabalho que deve ser concluído o mais rápido possível ou para problemas que rapidamente se resolve.

Para obter mais detalhes sobre como criar um JobInfo objeto, leia a documentação do Google para a JobInfo.Builder classe .

Passando parâmetros para um trabalho por meio do JobInfo

Os parâmetros são passados para um trabalho criando um PersistableBundle que é passado junto com o Job.Builder.SetExtras método :

var jobParameters = new PersistableBundle();
jobParameters.PutInt("LoopCount", 11);

var jobBuilder = this.CreateJobBuilderUsingJobId<DownloadJob>(1)
                     .SetExtras(jobParameters)
                     .Build();

O PersistableBundle é acessado da Android.App.Job.JobParameters.Extras propriedade no OnStartJob método de um JobService:

public override bool OnStartJob(JobParameters jobParameters)
{
    var loopCount = jobParams.Extras.GetInt("LoopCount", 10);
    
    // rest of code omitted
} 

Agendando um trabalho

Para agendar um trabalho, um aplicativo Xamarin.Android obterá uma referência ao serviço do JobScheduler sistema e chamará o JobScheduler.Schedule método com o JobInfo objeto que foi criado na etapa anterior. JobScheduler.Schedule retornará imediatamente com um dos dois valores inteiros:

  • JobScheduler.ResultSuccess – O trabalho foi agendado com êxito.
  • JobScheduler.ResultFailure – O trabalho não pôde ser agendado. Normalmente, isso é causado por parâmetros conflitantes JobInfo .

Esse código é um exemplo de agendamento de um trabalho e notificar o usuário sobre os resultados da tentativa de agendamento:

var jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
var scheduleResult = jobScheduler.Schedule(jobInfo);

if (JobScheduler.ResultSuccess == scheduleResult)
{
    var snackBar = Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_success, Snackbar.LengthShort);
    snackBar.Show();
}
else
{
    var snackBar = Snackbar.Make(FindViewById(Android.Resource.Id.Content), Resource.String.jobscheduled_failure, Snackbar.LengthShort);
    snackBar.Show();
}

Cancelando um trabalho

É possível cancelar todos os trabalhos que foram agendados ou apenas um único trabalho usando o JobsScheduler.CancelAll() método ou o JobScheduler.Cancel(jobId) método :

// Cancel all jobs
jobScheduler.CancelAll(); 

// to cancel a job with jobID = 1
jobScheduler.Cancel(1)

Resumo

Este guia discutiu como usar o Agendador de Trabalho do Android para executar o trabalho de forma inteligente em segundo plano. Ele discutiu como encapsular o trabalho a ser executado como um JobService e como usar o JobScheduler para agendar esse trabalho, especificando os critérios com um JobTrigger e como as falhas devem ser tratadas com um RetryStrategy.