Dispatcher de trabalho do Firebase
Este guia discute como agendar o trabalho em segundo plano usando a biblioteca Firebase Job Dispatcher do Google.
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 prolongada 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 vida útil 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 processará os resultados. Isso piora 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 (sondagem de um site) tornará o dispositivo inutilizável em um período relativamente curto de tempo.
O Android fornece as SEGUINTEs APIs para ajudar a executar o trabalho em segundo plano, mas por si só eles não são suficientes para o agendamento inteligente de trabalhos.
- 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.
- JobScheduler – o JobSchedule é uma ótima API que funciona com o sistema operacional para agendar trabalhos. No entanto, ele só está disponível para os aplicativos Android direcionados ao nível de API 21 ou superior.
- Receptores de Difusão – um aplicativo Android pode configurar receptores de difusão para executar o trabalho em resposta a eventos ou intenções em todo o sistema. No entanto, os receptores de difusão não fornecem nenhum controle sobre quando o trabalho deve ser executado. Além disso, as alterações no sistema operacional Android restringirão quando os receptores de difusão funcionarem ou os tipos de trabalho aos quais eles podem responder.
Há dois recursos principais para executar com eficiência o trabalho em segundo plano (às vezes chamado de trabalho em segundo plano ou um trabalho):
- Agendamento inteligente do trabalho – é importante que, quando um aplicativo está trabalhando 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 para ser executado quando as condições forem atendidas. Isso permite que o Android execute trabalho de forma inteligente. Por exemplo, as solicitações de rede podem ser executadas em lote ao mesmo tempo para fazer uso máximo da sobrecarga envolvida com a rede.
- 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 Firebase Job Dispatcher é uma biblioteca do Google que fornece uma API fluente para simplificar o agendamento de trabalho em segundo plano. Ele se destina a ser o substituto do Google Cloud Manager. O Firebase Job Dispatcher consiste nas seguintes APIs:
- Um
Firebase.JobDispatcher.JobService
é uma classe abstrata que deve ser estendida com a lógica que será executada no trabalho em segundo plano. - Um
Firebase.JobDispatcher.JobTrigger
declara quando o trabalho deve ser iniciado. Normalmente, isso é expresso como uma janela de tempo, por exemplo, aguarde pelo menos 30 segundos antes de iniciar o trabalho, mas execute o trabalho dentro de 5 minutos. - Um
Firebase.JobDispatcher.RetryStrategy
contém informações sobre o que deve ser feito quando um trabalho não é executado corretamente. A estratégia de repetição especifica quanto tempo aguardar antes de tentar executar o trabalho novamente. - Um
Firebase.JobDispatcher.Constraint
é um valor opcional que descreve uma condição que deve ser atendida antes que o trabalho possa ser executado, como se o dispositivo estivesse em uma rede não atendida ou carregando. - O
Firebase.JobDispatcher.Job
é uma API que unifica as APIs anteriores em para uma unidade de trabalho que pode ser agendada peloJobDispatcher
. AJob.Builder
classe é usada para instanciar umJob
. - Um
Firebase.JobDispatcher.JobDispatcher
usa as três APIs anteriores para agendar o trabalho com o sistema operacional e fornecer uma maneira de cancelar trabalhos, se necessário.
Para agendar o trabalho com o Firebase Job Dispatcher, um aplicativo Xamarin.Android deve encapsular o código em um tipo que estenda 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(IJobParameters parameters)
– Esse método é onde o trabalho ocorrerá e sempre deve ser implementado. Ele é executado no thread main. Esse método retornarátrue
se houver trabalho restante oufalse
se o trabalho for feito.bool OnStopJob(IJobParameters parameters)
– Isso é chamado quando o trabalho é interrompido por algum motivo. Ele deverá retornartrue
se o trabalho deve ser reagendado para mais tarde.JobFinished(IJobParameters parameters, bool needsReschedule)
– Esse método é chamado quando oJobService
concluiu qualquer trabalho assíncrono.
Para agendar um trabalho, o aplicativo criará uma instância de um JobDispatcher
objeto . Em seguida, um Job.Builder
é usado para criar um Job
objeto , que é fornecido para o JobDispatcher
que tentará agendar a execução do trabalho.
Este guia discutirá como adicionar o Firebase Job Dispatcher a um aplicativo Xamarin.Android e usá-lo para agendar o trabalho em segundo plano.
Requisitos
O Firebase Job Dispatcher requer o nível 9 ou superior da API do Android. A biblioteca Firebase Job Dispatcher depende de alguns componentes fornecidos pelo Google Play Services; o dispositivo deve ter o Google Play Services instalado.
Usando a Biblioteca de Dispatcher de Trabalhos do Firebase no Xamarin.Android
Para começar a usar o Firebase Job Dispatcher, primeiro adicione o pacote NuGet Xamarin.Firebase.JobDispatcher ao projeto Xamarin.Android. Pesquise no Gerenciador de Pacotes NuGet o pacote Xamarin.Firebase.JobDispatcher (que ainda está em pré-lançamento).
Depois de adicionar a biblioteca do Firebase Job Dispatcher, crie uma JobService
classe e agende-a para ser executada com uma instância do FirebaseJobDispatcher
.
Criando um JobService
Todo o trabalho executado pela biblioteca do Firebase Job Dispatcher deve ser feito em um tipo que estenda a Firebase.JobDispatcher.JobService
classe abstrata. A criação de um JobService
é muito semelhante à criação de um Service
com a estrutura do Android:
- Estender a
JobService
classe - Decore a subclasse com o
ServiceAttribute
. Embora não seja estritamente necessário, é recomendável definir explicitamente oName
parâmetro para ajudar na depuração doJobService
. - Adicione um
IntentFilter
para declarar oJobService
no AndroidManifest.xml. Isso também ajudará a biblioteca do Firebase Job Dispatcher a localizar e invocar oJobService
.
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.fjdtestapp.DemoJob")]
[IntentFilter(new[] {FirebaseJobServiceIntent.Action})]
public class DemoJob : JobService
{
static readonly string TAG = "X:DemoService";
public override bool OnStartJob(IJobParameters jobParameters)
{
Task.Run(() =>
{
// Work is happening asynchronously (code omitted)
});
// Return true because of the asynchronous work
return true;
}
public override bool OnStopJob(IJobParameters jobParameters)
{
Log.Debug(TAG, "DemoJob::OnStartJob");
// nothing to do.
return false;
}
}
Criando um FirebaseJobDispatcher
Antes que qualquer trabalho possa ser agendado, é necessário criar um Firebase.JobDispatcher.FirebaseJobDispatcher
objeto . O FirebaseJobDispatcher
é responsável por agendar um JobService
. O snippet de código a seguir é uma maneira de criar uma instância do FirebaseJobDispatcher
:
// This is the "Java" way to create a FirebaseJobDispatcher object
IDriver driver = new GooglePlayDriver(context);
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(driver);
No snippet de código anterior, a GooglePlayDriver
classe é que ajuda a FirebaseJobDispatcher
interagir com algumas das APIs de agendamento no Google Play Services no dispositivo. O parâmetro context
é qualquer Android Context
, como uma Atividade. Atualmente, o GooglePlayDriver
é a única IDriver
implementação na biblioteca do Firebase Job Dispatcher.
A associação Xamarin.Android para o Firebase Job Dispatcher fornece um método de extensão para criar um FirebaseJobDispatcher
do Context
:
FirebaseJobDispatcher dispatcher = context.CreateJobDispatcher();
Depois que o FirebaseJobDispatcher
tiver sido instanciado, é possível criar um Job
e executar o código na JobService
classe . O Job
é criado por um Job.Builder
objeto e será discutido na próxima seção.
Criando um Firebase.JobDispatcher.Job com o Job.Builder
A Firebase.JobDispatcher.Job
classe é responsável por encapsular os metadados necessários para executar um JobService
. UmJob
contém informações como qualquer restrição que deve ser atendida antes que o trabalho possa ser executado, se o Job
for recorrente ou quaisquer gatilhos que farão com que o trabalho seja executado. Como um mínimo, um Job
deve ter uma marca (uma cadeia de caracteres exclusiva que identifica o trabalho para o FirebaseJobDispatcher
) e o tipo do JobService
que deve ser executado. O Firebase Job Dispatcher criará uma instância do JobService
quando for a hora de executar o trabalho. Um Job
é criado usando uma instância da Firebase.JobDispatcher.Job.JobBuilder
classe .
O snippet de código a seguir é o exemplo mais simples de como criar um Job
usando a associação Xamarin.Android:
Job myJob = dispatcher.NewJobBuilder()
.SetService<DemoJob>("demo-job-tag")
.Build();
O Job.Builder
executará algumas verificações básicas de validação nos valores de entrada para o trabalho. Uma exceção será gerada se não for possível para o Job.Builder
criar um Job
. O Job.Builder
criará um Job
com os seguintes padrões:
- O tempo de vida de um
Job
(por quanto tempo ele será agendado para ser executado) é apenas até que o dispositivo seja reinicializado , depois que o dispositivo reinicializar oJob
for perdido. - Um
Job
não é recorrente – ele só será executado uma vez. - Um
Job
será agendado para ser executado assim que possível. - A estratégia de repetição padrão para um
Job
é usar uma retirada exponencial (discutida mais detalhadamente abaixo na seção Configurando uma RetryStrategy)
Agendando um trabalho
Depois de criar o Job
, ele precisa ser agendado com o FirebaseJobDispatcher
antes de ser executado. Há dois métodos para agendar um Job
:
// This will throw an exception if there was a problem scheduling the job
dispatcher.MustSchedule(myJob);
// This method will not throw an exception; an integer result value is returned
int scheduleResult = dispatcher.Schedule(myJob);
O valor retornado por FirebaseJobDispatcher.Schedule
será um dos seguintes valores inteiros:
FirebaseJobDispatcher.ScheduleResultSuccess
– OJob
foi agendado com êxito.FirebaseJobDispatcher.ScheduleResultUnknownError
– Ocorreu algum problema desconhecido que impediu que oJob
fosse agendado.FirebaseJobDispatcher.ScheduleResultNoDriverAvailable
– Um inválidoIDriver
foi usado ou oIDriver
estava de alguma forma indisponível.FirebaseJobDispatcher.ScheduleResultUnsupportedTrigger
– NãoTrigger
havia suporte para o .FirebaseJobDispatcher.ScheduleResultBadService
– O serviço não está configurado corretamente ou não está disponível.
Configurando um trabalho
É possível personalizar um trabalho. Exemplos de como um trabalho pode ser personalizado incluem o seguinte:
- Passando parâmetros para um trabalho – um
Job
pode exigir valores adicionais para executar seu trabalho, por exemplo, baixando um arquivo. - Definir Restrições – pode ser necessário executar apenas um trabalho quando determinadas condições forem atendidas. Por exemplo, execute apenas um
Job
quando o dispositivo estiver carregando. - Especificar quando um
Job
deve ser executado – o Firebase Job Dispatcher permite que os aplicativos especifiquem uma hora em que o trabalho deve ser executado. - Declarar uma estratégia de repetição para trabalhos com falha – uma estratégia de repetição fornece diretrizes para o
FirebaseJobDispatcher
sobre o que fazer comJobs
essa falha ao concluir.
Cada um desses tópicos será mais discutido nas seções a seguir.
Passando parâmetros para um trabalho
Os parâmetros são passados para um trabalho criando um Bundle
que é passado junto com o Job.Builder.SetExtras
método :
Bundle jobParameters = new Bundle();
jobParameters.PutInt(FibonacciCalculatorJob.FibonacciPositionKey, 25);
Job myJob = dispatcher.NewJobBuilder()
.SetService<DemoJob>("demo-job-tag")
.SetExtras(jobParameters)
.Build();
O Bundle
é acessado da IJobParameters.Extras
propriedade no OnStartJob
método :
public override bool OnStartJob(IJobParameters jobParameters)
{
int position = jobParameters.Extras.GetInt(FibonacciPositionKey, DEFAULT_VALUE);
// rest of code omitted
}
Configuração de restrições
As restrições podem ajudar a reduzir os custos ou o esvaziamento de bateria no dispositivo. A Firebase.JobDispatcher.Constraint
classe define essas restrições como valores inteiros:
Constraint.OnUnmeteredNetwork
– Execute o trabalho somente quando o dispositivo estiver conectado a uma rede não atendida. Isso é útil para impedir que o usuário incorre em encargos de dados.Constraint.OnAnyNetwork
– Execute o trabalho em qualquer rede à qual o dispositivo esteja conectado. Se especificado junto comConstraint.OnUnmeteredNetwork
, esse valor terá prioridade.Constraint.DeviceCharging
– Execute o trabalho somente quando o dispositivo estiver carregando.
As restrições são definidas com o Job.Builder.SetConstraint
método :
Job myJob = dispatcher.NewJobBuilder()
.SetService<DemoJob>("demo-job-tag")
.SetConstraint(Constraint.DeviceCharging)
.Build();
O JobTrigger
fornece diretrizes para o sistema operacional sobre quando o trabalho deve ser iniciado. Um JobTrigger
tem uma janela de execução que define um horário agendado para quando o Job
deve ser executado. A janela de execução tem um valor de janela inicial e um valor de janela final . A janela inicial é o número de segundos que o dispositivo deve aguardar antes de executar o trabalho e o valor da janela final é o número máximo de segundos a aguardar antes de executar o Job
.
Um JobTrigger
pode ser criado com o Firebase.Jobdispatcher.Trigger.ExecutionWindow
método . Por exemplo Trigger.ExecutionWindow(15,60)
, significa que o trabalho deve ser executado entre 15 e 60 segundos a partir de quando ele está agendado. O Job.Builder.SetTrigger
método é usado para
JobTrigger myTrigger = Trigger.ExecutionWindow(15,60);
Job myJob = dispatcher.NewJobBuilder()
.SetService<DemoJob>("demo-job-tag")
.SetTrigger(myTrigger)
.Build();
O padrão JobTrigger
para um trabalho é representado pelo valor Trigger.Now
, que especifica que um trabalho seja executado o mais rápido possível após o agendamento.
Configurando uma RetryStrategy
O Firebase.JobDispatcher.RetryStrategy
é usado para especificar quanto atraso um dispositivo deve usar antes de tentar executar novamente um trabalho com falha. Um RetryStrategy
tem uma política, que define qual algoritmo de base de tempo será usado para agendar novamente o trabalho com falha e uma janela de execução que especifica uma janela na qual o trabalho deve ser agendado. Essa janela de reagendamento é definida por dois valores. O primeiro valor é o número de segundos a aguardar antes de reagendar o trabalho (o valor inicial de retirada ) e o segundo número é o número máximo de segundos antes que o trabalho precise ser executado (o valor máximo de retirada ).
Os dois tipos de políticas de repetição são identificados por esses valores int:
RetryStrategy.RetryPolicyExponential
– 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 de _initial 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. O padrãoRetryStrategy
para a biblioteca do Firebase Job Dispatcher é representado peloRetryStrategy.DefaultExponential
objeto . Ele tem uma retirada inicial de 30 segundos e uma retirada máxima de 3600 segundos.RetryStrategy.RetryPolicyLinear
– 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. A biblioteca do Firebase Job Dispatcher define umRetryStrategy.DefaultLinear
que tem uma janela de reagendamento de pelo menos 30 segundos e até 3600 segundos.
É possível definir um personalizado RetryStrategy
com o FirebaseJobDispatcher.NewRetryStrategy
método . Ele usa três parâmetros:
int policy
– A política é um dos valores anterioresRetryStrategy
,RetryStrategy.RetryPolicyLinear
ouRetryStrategy.RetryPolicyExponential
.int initialBackoffSeconds
– A retirada inicial é um atraso, em segundos, que é necessário antes de tentar executar o trabalho novamente. O valor padrão para isso é 30 segundos.int maximumBackoffSeconds
– O valor máximo de retirada declara o número máximo de segundos para atrasar antes de tentar executar o trabalho novamente. O valor padrão é 3600 segundos.
RetryStrategy retry = dispatcher.NewRetryStrategy(RetryStrategy.RetryPolicyLinear, initialBackoffSeconds, maximumBackoffSet);
// Create a Job and set the RetryStrategy via the Job.Builder
Job myJob = dispatcher.NewJobBuilder()
.SetService<DemoJob>("demo-job-tag")
.SetRetryStrategy(retry)
.Build();
Cancelando um trabalho
É possível cancelar todos os trabalhos que foram agendados ou apenas um único trabalho usando o FirebaseJobDispatcher.CancelAll()
método ou o FirebaseJobDispatcher.Cancel(string)
método :
int cancelResult = dispatcher.CancelAll();
// to cancel a single job:
int cancelResult = dispatcher.Cancel("unique-tag-for-job");
Qualquer um dos métodos retornará um valor inteiro:
FirebaseJobDispatcher.CancelResultSuccess
– O trabalho foi cancelado com êxito.FirebaseJobDispatcher.CancelResultUnknownError
– Um erro impediu que o trabalho fosse cancelado.FirebaseJobDispatcher.CancelResult.NoDriverAvailable
– OFirebaseJobDispatcher
não pode cancelar o trabalho, pois não há nenhum válidoIDriver
disponível.
Resumo
Este guia discutiu como usar o Firebase Job Dispatcher 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 FirebaseJobDispatcher
para agendar esse trabalho, especificando os critérios com um JobTrigger
e como as falhas devem ser tratadas com um RetryStrategy
.