Utilità di pianificazione di processo Android

Questa guida illustra come pianificare il lavoro in background usando l'API Dell'utilità di pianificazione processi Android, disponibile nei dispositivi Android che eseguono Android 5.0 (livello API 21) e versioni successive.

Panoramica

Uno dei modi migliori per mantenere reattiva un'applicazione Android all'utente consiste nel garantire che il lavoro complesso o a esecuzione prolungata venga eseguito in background. Tuttavia, è importante che il lavoro in background non influisca negativamente sull'esperienza dell'utente con il dispositivo.

Ad esempio, un processo in background potrebbe eseguire il polling di un sito Web ogni tre o quattro minuti per eseguire una query per le modifiche apportate a un determinato set di dati. Questo sembra benigno, tuttavia avrebbe un impatto disastroso sulla durata della batteria. L'applicazione riattiva ripetutamente il dispositivo, eleva la CPU a uno stato di alimentazione superiore, accende le radio, effettua le richieste di rete e quindi elabora i risultati. Peggiora perché il dispositivo non si spegne immediatamente e torna allo stato di inattività a basso consumo. Il lavoro in background pianificato in modo non adeguato può inavvertitamente mantenere il dispositivo in uno stato con requisiti di alimentazione non necessari ed eccessivi. Questa attività apparentemente innocente (polling di un sito Web) rende il dispositivo inutilizzabile in un periodo di tempo relativamente breve.

Android fornisce le API seguenti per facilitare l'esecuzione del lavoro in background, ma da soli non sono sufficienti per la pianificazione intelligente dei processi.

  • Servizi finalità: i servizi finalità sono ideali per l'esecuzione del lavoro, ma non consentono di pianificare il lavoro.
  • AlarmManager : queste API consentono solo di pianificare il lavoro, ma non consentono di eseguire effettivamente il lavoro. Inoltre, AlarmManager consente solo vincoli basati sul tempo, il che significa generare un allarme in un determinato momento o dopo un determinato periodo di tempo è trascorso.
  • Ricevitori di trasmissione: un'app Android può configurare ricevitori di trasmissione per eseguire operazioni in risposta a eventi o finalità a livello di sistema. Tuttavia, i ricevitori di trasmissione non forniscono alcun controllo su quando deve essere eseguito il processo. Inoltre, le modifiche apportate al sistema operativo Android limiteranno quando i ricevitori di trasmissione funzioneranno o i tipi di lavoro a cui possono rispondere.

Esistono due funzionalità chiave per eseguire in modo efficiente il lavoro in background (talvolta definito processo in background o processo):

  1. Pianificazione intelligente del lavoro : è importante che quando un'applicazione esegue il lavoro in background che lo fa come un buon cittadino. Idealmente, l'applicazione non deve richiedere l'esecuzione di un processo. L'applicazione deve invece specificare le condizioni che devono essere soddisfatte per quando il processo può essere eseguito e quindi pianificare il processo con il sistema operativo che eseguirà il lavoro quando vengono soddisfatte le condizioni. In questo modo Android può eseguire il processo per garantire la massima efficienza nel dispositivo. Ad esempio, le richieste di rete possono essere raggruppate per l'esecuzione contemporaneamente per sfruttare al massimo il sovraccarico necessario per la rete.
  2. Incapsulamento del lavoro : il codice per eseguire il lavoro in background deve essere incapsulato in un componente discreto che può essere eseguito indipendentemente dall'interfaccia utente e sarà relativamente facile da riprogrammare se il lavoro non viene completato per qualche motivo.

L'Utilità di pianificazione processi Android è un framework integrato nel sistema operativo Android che fornisce un'API Fluent per semplificare la pianificazione del lavoro in background. L'Utilità di pianificazione processi Android è costituita dai tipi seguenti:

  • Android.App.Job.JobScheduler è un servizio di sistema usato per pianificare, eseguire e, se necessario, annullare i processi per conto di un'applicazione Android.
  • È Android.App.Job.JobService una classe astratta che deve essere estesa con la logica che eseguirà il processo nel thread principale dell'applicazione. Ciò significa che è JobService responsabile del modo in cui il lavoro deve essere eseguito in modo asincrono.
  • Un Android.App.Job.JobInfo oggetto contiene i criteri per guidare Android quando il processo deve essere eseguito.

Per pianificare l'uso dell'Utilità di pianificazione processi Android, un'applicazione Xamarin.Android deve incapsulare il codice in una classe che estende la JobService classe . JobService ha tre metodi del ciclo di vita che possono essere chiamati durante la durata del processo:

  • bool OnStartJob(Parametri JobParameters): questo metodo viene chiamato da JobScheduler per eseguire il lavoro ed eseguito sul thread principale dell'applicazione. È responsabilità dell'utente JobService eseguire in modo asincrono il lavoro e restituire true se è presente un lavoro rimanente o false se il lavoro viene eseguito.

    Quando chiama JobScheduler questo metodo, richiederà e manterrà un wakelock da Android per la durata del processo. Al termine del processo, è responsabilità dell'utente JobService indicare questo JobScheduler fatto chiamando il JobFinished metodo (descritto di seguito).

  • JobFinished(Parametri JobParameters, bool needsReschedule): questo metodo deve essere chiamato da JobService per indicare JobScheduler che il lavoro è stato eseguito. Se JobFinished non viene chiamato, il JobScheduler non rimuoverà il wakelock, causando inutili scaricamento della batteria.

  • bool OnStopJob(Parametri JobParameters): viene chiamato quando il processo viene arrestato prematuramente da Android. Deve restituire true se il processo deve essere riprogrammato in base ai criteri di ripetizione dei tentativi (descritti di seguito in modo più dettagliato).

È possibile specificare vincoli o trigger che controllano quando un processo può o deve essere eseguito. Ad esempio, è possibile vincolare un processo in modo che venga eseguito solo quando il dispositivo viene ricaricato o per avviare un processo quando viene scattata un'immagine.

Questa guida illustra in dettaglio come implementare una JobService classe e pianificarla con .JobScheduler

Requisiti

L'Utilità di pianificazione processi Android richiede il livello API Android 21 (Android 5.0) o versione successiva.

Uso dell'utilità di pianificazione dei processi Android

Esistono tre passaggi per l'uso dell'API JobScheduler Android:

  1. Implementare un tipo JobService per incapsulare il lavoro.
  2. Utilizzare un JobInfo.Builder oggetto per creare l'oggetto JobInfo che conterrà i criteri per l'esecuzione JobScheduler del processo.
  3. Pianificare il processo usando JobScheduler.Schedule.

Implementare un jobService

Tutte le operazioni eseguite dalla libreria dell'Utilità di pianificazione processi Android devono essere eseguite in un tipo che estende la Android.App.Job.JobService classe astratta. La creazione di un JobService oggetto è molto simile alla creazione di un Service con il framework Android:

  1. Estendere la classe JobService.
  2. Decorare la sottoclasse con ServiceAttribute e impostare il Name parametro su una stringa costituita dal nome del pacchetto e dal nome della classe (vedere l'esempio seguente).
  3. Impostare la Permission proprietà sull'oggetto ServiceAttribute sulla stringa android.permission.BIND_JOB_SERVICE.
  4. Eseguire l'override del OnStartJob metodo aggiungendo il codice per eseguire il lavoro. Android richiamerà questo metodo sul thread principale dell'applicazione per eseguire il processo. Il lavoro che richiederà più tempo per alcuni millisecondi deve essere eseguito su un thread per evitare di bloccare l'applicazione.
  5. Al termine del lavoro, deve JobService chiamare il JobFinished metodo . Questo metodo indica JobService che il JobScheduler lavoro viene eseguito. La mancata chiamata JobFinished comporterà l'inserimento JobService di richieste non necessarie sul dispositivo, riducendo la durata della batteria.
  6. È consigliabile eseguire anche l'override del OnStopJob metodo . Questo metodo viene chiamato da Android quando il processo viene arrestato prima del completamento e offre la JobService possibilità di eliminare correttamente le risorse. Questo metodo deve restituire true se è necessario riprogrammare il processo o false se non è consigliabile eseguire nuovamente il processo.

Il codice seguente è un esempio del più semplice JobService per un'applicazione, usando il TPL per eseguire in modo asincrono alcune operazioni:

[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; 
    }
}

Creazione di un elemento JobInfo per pianificare un processo

Le applicazioni Xamarin.Android non creano un'istanza diretta di , JobService ma passano un JobInfo oggetto a JobScheduler. Verrà JobScheduler creata un'istanza dell'oggetto richiesto JobService , della pianificazione e dell'esecuzione di JobService in base ai metadati in JobInfo. Un JobInfo oggetto deve contenere le informazioni seguenti:

  • JobId : valore int usato per identificare un processo in JobScheduler. Il riutilizzo di questo valore aggiornerà tutti i processi esistenti. Il valore deve essere univoco per l'applicazione.
  • JobService : questo parametro è un ComponentName oggetto che identifica in modo esplicito il tipo da JobScheduler usare per eseguire un processo.

Questo metodo di estensione illustra come creare un JobInfo.Builder oggetto con un oggetto Android Context, ad esempio un'attività:

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.

Una potente funzionalità dell'Utilità di pianificazione processi Android è la possibilità di controllare quando un processo viene eseguito o in quali condizioni può essere eseguito un processo. La tabella seguente descrive alcuni dei metodi su JobInfo.Builder che consentono a un'app di influenzare quando un processo può essere eseguito:

metodo Descrizione
SetMinimumLatency Specifica che un ritardo (in millisecondi) che deve essere osservato prima dell'esecuzione di un processo.
SetOverridingDeadline Dichiara che il processo deve essere eseguito prima che sia trascorso questo tempo (in millisecondi).
SetRequiredNetworkType Specifica i requisiti di rete per un processo.
SetRequiresBatteryNotLow Il processo può essere eseguito solo quando il dispositivo non visualizza un avviso di "batteria insufficiente" all'utente.
SetRequiresCharging Il processo può essere eseguito solo quando la batteria è carica.
SetDeviceIdle Il processo verrà eseguito quando il dispositivo è occupato.
SetPeriodic Specifica che il processo deve essere eseguito regolarmente.
SetPersisted Il processo deve essere perisist tra i riavvii del dispositivo.

SetBackoffCriteria Fornisce alcune indicazioni su quanto tempo JobScheduler deve attendere prima di provare a eseguire di nuovo un processo. Esistono due parti dei criteri di backoff: un ritardo in millisecondi (valore predefinito di 30 secondi) e tipo di backoff da usare (talvolta definito criterio di backoff o criteri di ripetizione dei tentativi). I due criteri sono incapsulati nell'enumerazione Android.App.Job.BackoffPolicy :

  • BackoffPolicy.Exponential : un criterio di backoff esponenziale aumenterà il valore di backoff iniziale in modo esponenziale dopo ogni errore. La prima volta che un processo ha esito negativo, la libreria attenderà l'intervallo iniziale specificato prima di riprogrammare il processo, ad esempio 30 secondi. La seconda volta che il processo ha esito negativo, la libreria attenderà almeno 60 secondi prima di provare a eseguire il processo. Dopo il terzo tentativo non riuscito, la libreria attenderà 120 secondi e così via. Questo è il valore predefinito.
  • BackoffPolicy.Linear : questa strategia è un backoff lineare che il processo deve essere riprogrammato per l'esecuzione a intervalli impostati (fino a quando non riesce). Il backoff lineare è più adatto per il lavoro che deve essere completato il prima possibile o per i problemi che si risolvono rapidamente.

Per altri dettagli sulla creazione di un JobInfo oggetto, leggere la documentazione di Google per la JobInfo.Builder classe.

Passaggio di parametri a un processo tramite JobInfo

I parametri vengono passati a un processo creando un PersistableBundle oggetto passato insieme al Job.Builder.SetExtras metodo :

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

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

L'oggetto PersistableBundleAndroid.App.Job.JobParameters.Extras è accessibile dalla proprietà nel OnStartJob metodo di un JobServiceoggetto :

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

Programmazione di un processo

Per pianificare un processo, un'applicazione Xamarin.Android otterrà un riferimento al JobScheduler servizio di sistema e chiamerà il JobScheduler.Schedule metodo con l'oggetto JobInfo creato nel passaggio precedente. JobScheduler.Schedule restituirà immediatamente con uno dei due valori integer:

  • JobScheduler.ResultSuccess : il processo è stato pianificato correttamente.
  • JobScheduler.ResultFailure : impossibile pianificare il processo. Questo è in genere causato da parametri in conflitto JobInfo .

Questo codice è un esempio di pianificazione di un processo e notifica all'utente dei risultati del tentativo di pianificazione:

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();
}

Annullamento di un processo

È possibile annullare tutti i processi pianificati o solo un singolo processo usando il JobsScheduler.CancelAll() metodo o il JobScheduler.Cancel(jobId) metodo :

// Cancel all jobs
jobScheduler.CancelAll(); 

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

Riepilogo

Questa guida ha illustrato come usare l'Utilità di pianificazione processi Android per eseguire in modo intelligente il lavoro in background. Ha illustrato come incapsulare il lavoro da eseguire come e JobService come usare JobScheduler per pianificare il lavoro, specificando i criteri con un JobTrigger e come gestire gli errori con un oggetto RetryStrategy.