Programador de trabajos de Android

En esta guía se describe cómo programar el trabajo en segundo plano mediante android Job Scheduler API, que está disponible en dispositivos Android que ejecutan Android 5.0 (nivel de API 21) y versiones posteriores.

Información general

Una de las mejores maneras de mantener una aplicación Android con capacidad de respuesta para el usuario es asegurarse de que el trabajo complejo o de larga duración se realiza en segundo plano. Sin embargo, es importante que el trabajo en segundo plano no afectará negativamente a la experiencia del usuario con el dispositivo.

Por ejemplo, un trabajo en segundo plano podría sondear un sitio web cada tres o cuatro minutos para consultar los cambios en un conjunto de datos determinado. Esto parece benigno, pero tendría un impacto desastroso en la duración de la batería. La aplicación reactivará repetidamente el dispositivo, elevará la CPU a un estado de energía superior, encenderá las radios, realizará las solicitudes de red y, a continuación, procesará los resultados. Se pone peor porque el dispositivo no se encenderá inmediatamente y volverá al estado de inactividad de bajo consumo. Un trabajo en segundo plano mal programado puede mantener accidentalmente el dispositivo en un estado con requisitos de energía innecesarios y excesivos. Esta actividad aparentemente insoportable (sondear un sitio web) hará que el dispositivo sea inutilizable en un período de tiempo relativamente corto.

Android proporciona las siguientes API para ayudar a realizar el trabajo en segundo plano, pero por sí solos no son suficientes para la programación inteligente de trabajos.

  • Intent Services: los servicios de intención son excelentes para realizar el trabajo, pero no proporcionan ninguna manera de programar el trabajo.
  • AlarmManager: estas API solo permiten programar el trabajo, pero no proporcionan ninguna manera de realizar realmente el trabajo. Además, AlarmManager solo permite restricciones basadas en el tiempo, lo que significa que se genera una alarma en un momento determinado o después de que haya transcurrido un determinado período de tiempo.
  • Receptores de difusión: una aplicación Android puede configurar receptores de difusión para realizar el trabajo en respuesta a eventos o intenciones de todo el sistema. Sin embargo, los receptores de difusión no proporcionan ningún control sobre cuándo se debe ejecutar el trabajo. Además, los cambios en el sistema operativo Android restringirán cuándo funcionarán los receptores de difusión o los tipos de trabajo a los que pueden responder.

Hay dos características clave para realizar eficazmente el trabajo en segundo plano (a veces denominado trabajo en segundo plano otrabajo):

  1. Programación inteligente del trabajo: es importante que, cuando una aplicación está realizando trabajo en segundo plano, lo haga como un buen ciudadano. Lo ideal es que la aplicación no exija que se ejecute un trabajo. En su lugar, la aplicación debe especificar las condiciones que se deben cumplir para cuando se pueda ejecutar el trabajo y, a continuación, programar ese trabajo con el sistema operativo que realizará el trabajo cuando se cumplen las condiciones. Esto permite a Android ejecutar el trabajo para garantizar la máxima eficacia en el dispositivo. Por ejemplo, las solicitudes de red se pueden procesar por lotes para que se ejecuten todas al mismo tiempo con el fin de aprovechar al máximo la sobrecarga que implica la red.
  2. Encapsular el trabajo: el código para realizar el trabajo en segundo plano debe encapsularse en un componente discreto que se pueda ejecutar independientemente de la interfaz de usuario y será relativamente fácil de volver a programar si el trabajo no se completa por algún motivo.

Android Job Scheduler es un marco integrado en el sistema operativo Android que proporciona una API fluida para simplificar la programación del trabajo en segundo plano. Android Job Scheduler consta de los siguientes tipos:

  • es un servicio del sistema que se usa para programar, ejecutar y, si es necesario, cancelar trabajos en Android.App.Job.JobScheduler nombre de una aplicación Android.
  • es Android.App.Job.JobService una clase abstracta que se debe extender con la lógica que ejecutará el trabajo en el subproceso principal de la aplicación. Esto significa que es responsable de cómo se va a realizar el JobService trabajo de forma asincrónica.
  • Un Android.App.Job.JobInfo objeto contiene los criterios para guiar a Android cuando se debe ejecutar el trabajo.

Para programar el trabajo con android Job Scheduler, una aplicación de Xamarin.Android debe encapsular el código en una clase que extienda la JobService clase . JobService tiene tres métodos de ciclo de vida a los que se puede llamar durante la vigencia del trabajo:

  • bool OnStartJob(Parámetros de JobParameters): llama a este método para realizar el trabajo y se ejecuta en el subproceso principal de la aplicación. Es responsabilidad de la tarea realizar el trabajo de forma asincrónica y devolver si queda trabajo o si JobService el trabajo se ha truefalse realizado.

    Cuando llama JobScheduler a este método, solicitará y conservará un wakelock desde Android mientras dure el trabajo. Una vez finalizado el trabajo, es responsabilidad de la propiedad de saber de este hecho mediante una llamada JobServiceJobScheduler al método JobFinished (que se describe a continuación).

  • JobFinished(Parámetros JobParameters, bool needsReschedule): el debe llamar a este método para que le informe de que el trabajo se ha JobScheduler realizado. Si JobFinished no se llama a , no quitará el bloqueo de JobScheduler reactivación, lo que provocará una purga innecesaria de la batería.

  • bool OnStopJob(parámetros JobParameters): se llama a este método cuando Android detiene prematuramente el trabajo. Debe devolver si el trabajo se debe volver a programar en función de los criterios de reintento true (se describe a continuación con más detalle).

Es posible especificar restricciones o desencadenadoresque controlarán cuándo se puede o debe ejecutar un trabajo. Por ejemplo, es posible restringir un trabajo para que solo se ejecute cuando el dispositivo cargue o inicie un trabajo cuando se toma una imagen.

En esta guía se explica en detalle cómo implementar una JobService clase y programarla con JobScheduler .

Requisitos

La versión Job Scheduler Android requiere el nivel de API de Android 21 (Android 5.0) o superior.

Uso de android Job Scheduler

Hay tres pasos para usar la API JobScheduler de Android:

  1. Implemente un tipo JobService para encapsular el trabajo.
  2. Use un JobInfo.Builder objeto para crear el objeto que JobInfo contendrán los criterios para que ejecute JobScheduler el trabajo.
  3. Programe el trabajo mediante JobScheduler.Schedule .

Implementación de un jobService

Todo el trabajo realizado por la biblioteca Job Scheduler Android debe realizarse en un tipo que extienda la Android.App.Job.JobService clase abstracta. La creación JobService de un es muy similar a la creación de un con android Service framework:

  1. Extienda la JobService clase .
  2. Decore la subclase con y establezca el parámetro en una cadena que se conste del nombre del paquete y el nombre de la ServiceAttributeName clase (vea el ejemplo siguiente).
  3. Establezca la Permission propiedad en en la cadena ServiceAttributeandroid.permission.BIND_JOB_SERVICE .
  4. Invalide OnStartJob el método y agregue el código para realizar el trabajo. Android invocará este método en el subproceso principal de la aplicación para ejecutar el trabajo. Trabajo que tarda más de unos milisegundos en realizarse en un subproceso para evitar el bloqueo de la aplicación.
  5. Cuando se realiza el trabajo, JobService debe llamar al método JobFinished . Este método indica JobService cómo se realiza el JobScheduler trabajo. Si no se JobFinished llama, se colocarán demandas innecesarias en el dispositivo, lo que reducirá JobService la duración de la batería.
  6. Es una buena idea invalidar también el OnStopJob método . Android llama a este método cuando el trabajo se está cerrando antes de que finalice y proporciona la oportunidad de eliminar correctamente JobService los recursos. Este método debe devolver si es necesario volver a programar el trabajo o si no es conveniente true volver a ejecutar el false trabajo.

El código siguiente es un ejemplo del más sencillo para una aplicación, mediante TPL para realizar de forma asincrónica JobService algún trabajo:

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

Creación de un JobInfo para programar un trabajo

Las aplicaciones de Xamarin.Android no crea una instancia de directamente, sino que pasan JobService un objeto a JobInfoJobScheduler . crea JobScheduler una instancia del objeto JobService solicitado, programando y ejecutando JobService según los metadatos de JobInfo . Un JobInfo objeto debe contener la siguiente información:

  • JobId: se trata de un valor que se usa para identificar un trabajo en JobScheduler . La nueva aplicación de este valor actualizará los trabajos existentes. El valor debe ser único para la aplicación.
  • JobService: este parámetro es un que identifica explícitamente el tipo que debe usar para ejecutar un JobScheduler trabajo.

Este método de extensión muestra cómo crear un con JobInfo.Builder un Context Android, como una actividad:

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 característica eficaz de android Job Scheduler es la capacidad de controlar cuándo se ejecuta un trabajo o en qué condiciones se puede ejecutar un trabajo. En la tabla siguiente se describen algunos de los métodos en que permiten JobInfo.Builder que una aplicación influya en cuándo se puede ejecutar un trabajo:

Método Descripción
SetMinimumLatency Especifica que se debe observar un retraso (en milisegundos) antes de ejecutar un trabajo.
SetOverridingDeadline Declara que el trabajo debe ejecutarse antes de que transcurra este tiempo (en milisegundos).
SetRequiredNetworkType Especifica los requisitos de red para un trabajo.
SetRequiresBatteryNotLow El trabajo solo se puede ejecutar cuando el dispositivo no muestra una advertencia de "batería baja" al usuario.
SetRequiresCharging El trabajo solo se puede ejecutar cuando se carga la batería.
SetDeviceIdle El trabajo se ejecutará cuando el dispositivo esté ocupado.
SetPeriodic Especifica que el trabajo se debe ejecutar con regularidad.
SetPersisted El trabajo debe persist en los reinicios del dispositivo.

proporciona SetBackoffCriteria algunas instrucciones sobre cuánto tiempo debe esperar antes de intentar ejecutar un trabajo de JobScheduler nuevo. Hay dos partes en los criterios de retraso: un retraso en milisegundos (valor predeterminado de 30 segundos) y el tipo de desuso que se debe usar (a veces denominado directiva de retraso o directiva de reintentos). Las dos directivas se encapsulan en la Android.App.Job.BackoffPolicy enumeración :

  • BackoffPolicy.Exponential : una directiva de retroceso exponencial aumentará exponencialmente el valor de retroceso inicial después de cada error. La primera vez que se produce un error en un trabajo, la biblioteca esperará el intervalo inicial especificado antes de reprogramar el trabajo: ejemplo 30 segundos. La segunda vez que se produce un error en el trabajo, la biblioteca esperará al menos 60 segundos antes de intentar ejecutar el trabajo. Después del tercer intento con error, la biblioteca esperará 120 segundos, y así sucesivamente. Este es el valor predeterminado.
  • BackoffPolicy.Linear : esta estrategia es un respaldo lineal que el trabajo se debe volver a programar para ejecutarse a intervalos establecidos (hasta que se realiza correctamente). El respaldo lineal es más adecuado para el trabajo que se debe completar lo antes posible o para los problemas que se resolverán rápidamente.

Para obtener más información sobre cómo JobInfo crear un objeto, lea JobInfo.

Pasar parámetros a un trabajo a través de JobInfo

Los parámetros se pasan a un trabajo mediante la creación PersistableBundle de un que se pasa junto con el método Job.Builder.SetExtras :

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

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

Se PersistableBundle tiene acceso a desde la propiedad en el método de Android.App.Job.JobParameters.ExtrasOnStartJobJobService :

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

Programación de un trabajo

Para programar un trabajo, una aplicación de Xamarin.Android obtiene una referencia al servicio del sistema y llama al método con el objeto que se creó JobSchedulerJobScheduler.Schedule en el paso JobInfo anterior. JobScheduler.Schedule devolverá inmediatamente con uno de los dos valores enteros:

  • JobScheduler.ResultSuccess: el trabajo se ha programado correctamente.
  • JobScheduler.ResultFailure: no se pudo programar el trabajo. Esto suele deberse a parámetros en JobInfo conflicto.

Este código es un ejemplo de programación de un trabajo y notificación al usuario de los resultados del intento de programación:

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

Cancelación de un trabajo

Es posible cancelar todos los trabajos que se han programado, o simplemente un único trabajo mediante el JobsScheduler.CancelAll() método o el método JobScheduler.Cancel(jobId) :

// Cancel all jobs
jobScheduler.CancelAll(); 

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

Resumen

En esta guía se ha analizado cómo usar android Job Scheduler realizar trabajo de forma inteligente en segundo plano. Se ha analizado cómo encapsular el trabajo que se va a realizar como y cómo usar para programar ese trabajo, especificando los criterios con y cómo se deben controlar los errores con JobServiceJobSchedulerJobTriggerRetryStrategy .