Windows Phone 7.5: Tareas en segundo plano (2 de 2)

Hola a todos!

En el post anterior vimos como trabajar con una parte del api de Acciones Programadas: las notificaciones programadas. Si te lo perdiste, puedes verlo aquí.

En este segundo post vamos a aprender a trabajar con tareas programas. Estas tareas programadas nos permiten ejecutar código en segundo plano y sin tener nuestra aplicación iniciada. A la hora de usar las tareas programadas podremos elegir entre dos tipos diferentes, las tareas periódicas, basadas en el objeto PeriodicTask, o las tareas intensivas, basadas en el objeto ResourceIntensiveTask.

Microsoft ha dejado muy claro varias veces que no desea que nuestro terminal se quede sin batería o se sature debido a procesos en segundo plano. Debido a esto, existen ciertas limitaciones en el uso de tareas programadas que deberemos tener muy en cuenta al usarlas. En primer lugar, común a ambos tipos de tareas, nos encontraremos con una limitación en el consumo de memoria. En cualquier momento de su ejecución, nuestra tarea programada no puede consumir más de 5Mb de memoria, si superamos este límite, el sistema se encargará, automáticamente y sin previo aviso de terminar la ejecución de la tarea. También tenemos un tiempo de vida máximo, al igual que en las notificaciones. Disponemos de una propiedad ExpirationTime, pero en este caso, la fecha nunca podrá ser superior a dos semanas desde la fecha establecida en la propiedad BeginTime.

También nos encontraremos con restricciones en las apis que podemos usar desde las tareas programadas:

Namespace

Api

Microsoft.Devices
Camera
VibrateController
NowPlaying
Microsoft.Devices.Radio
Namespace completo
Microsoft.Devices.Sensonrs
Namespace completo
Microsoft.Phone.BackgroundAudio
BackgroundAudioPlayer
Microsoft.Phone.BackgroundTransfer Add(BackgroundTransferRequest)
Microsoft.Phone.Controls WebBrowser
Microsoft.Phone.Info IsKeyboardDeployed
Microsoft.Phone.Scheduler Add(SchedulerAction)
Micrososft.Phone.Tasks
Namespace completo
Microsoft.Xna Namespace completo
System.Windows MessageBox
System.Windows.Controls MediaElement
MultiScaleImage
System.Windows.Media LicenseAcquirer
A/V Capture
System.Windows.Navigation Namespace completo

Duración, intervalo y límite de instalación

A nivel particular, cada uno de los tipos de tareas programadas cuenta con restricciones en la duración de ejecución, el intervalo de lanzamiento y el límite de tareas del mismo tipo que soporta Windows Phone 7.5.

Las tareas periódicas, PeriodicTask, tienen una duración máxima por ejecución de 15 segundos, tiempo después del cual es terminada por el sistema automáticamente. Cuentan con un intervalo de lanzamiento de 30 minutos, que puede sufrir desviaciones hasta de 10 minutos. Esto es así porque, para ahorrar batería, el sistema agrupa la ejecución de varias tareas periódicas. Tenemos un límite por dispositivo, sin determinar de forma general, que puede ser tan bajo como 6 tareas periódicas. Además pasado cierto número de tareas periódicas, el sistema avisará al usuario de que su batería se consumirá más rápidamente por tener múltiples tareas en segundo plano. Por último, si se activa el modo de ahorro de batería, todas las tareas periódicas se cancelan automáticamente.

Las tareas intensivas, ResourceIntensiveTask, tienen una duración mayor de ejecución, de hasta 10 minutos. Al igual que las tareas periódicas, pasado el tiempo máximo de ejecución, nuestra tarea será terminada por el sistema. En este caso, el sistema no agrupa las tareas, lanza cada una de forma independiente y mientras se está ejecutando una tarea intensiva no se pueden ejecutar otras, lo que puede provocar que nuestra tarea no se lance en ciertos momentos que debería. A este hecho hay que añadir ciertas restricciones muy severas sobre el estado del dispositivo, así, para que nuestra tarea se ejecute debemos cumplir tres requisitos: estar conectados a una red Wi Fi, estar conectados a alimentación de energía externa y que el nivel de batería se sitúe por encima del 90%.

Por todas estas limitaciones en el uso de las tareas en segundo plano, debemos estar preparados para una posibilidad: que no se ejecuten nunca o que no lo hagan cuando nosotros hemos ordenado. Tenemos que controlar este hecho y preparar nuestra aplicación para tomar las medidas necesarias para seguir trabajando sin la ejecución de las tareas.

Creación de una tarea en segundo plano

Como regla general, una aplicación Windows Phone solo puede definir una tarea de ejecución en segundo plano, más conocida como agente. La parte buena de esto es que un mismo agente puede ser registrado como tarea periódica o intensiva, solo cambiando la forma en la que la activamos y lanzamos.

Lo primero que necesitamos es crear un nuevo proyecto de Silverlight para Windows Phone y a continuación añadir a la solución un proyecto del tipo Windows Phone Scheduled Task Agent:

image

 

Este será el agente que usaremos para ejecutar nuestro código en segundo plano. Solo tenemos que añadir una referencia en nuestra aplicación al agente, usando el menu Add Reference y seleccionando el proyecto del agente en la pestaña “projects”.

Si abrimos el archivo ScheduledAgent.cs de nuestro agente veremos que ya existen una serie de métodos creados:

  • OnInvoke: Cuando el sistema comience la ejecución del agente, llamará a este método.
  • ScheduledAgent_UnhandledException: En este método recibiremos todas las excepciones no manejadas por nuestro código.
  • ScheduledAgent: El constructor de la clase.

Si nos fijamos en el método OnInvoke veremos lo siguiente:

protected override void OnInvoke(ScheduledTask task)
{
    //TODO: Add code to perform your task in background

    NotifyComplete();
}

Por defecto tenemos una llamada al método NotifyComplete, este método se encarga de notificar al sistema que se ha terminado la ejecución del agente, es importante llamarlo o el sistema no sabrá que hemos concluido y, pasado el tiempo máximo terminará automáticamente el proceso.

Como vimos anteriormente, en un agente no tenemos soporte para comunicarnos con el usuario usando la clase MessageBox, por ello, vamos a usar la clase ShellToast para poder enviar un aviso al usuario cuando se llame al método OnInvoke., lo primero que debemos hacer es añadir un using a Microsoft.Phone.Shell en nuestro agente y a continuación crear el mensaje y mostrarlo:

protected override void OnInvoke(ScheduledTask task)
{
    //TODO: Add code to perform your task in background
    ShellToast mensaje = new ShellToast();
    mensaje.Title = "Notificación";
    mensaje.Content = "Hola desde una tarea";
    mensaje.NavigationUri = new System.Uri("/MainPage.xaml", System.UriKind.Relative);
    mensaje.Show();
    NotifyComplete();
}

Lo mejor de la clase ShellToast es que, además de facilitar un mensaje al usuario, podemos definir una Uri de nuestra aplicación a la que el usuario será dirigido cuando pulse sobre la notificación, pudiendo de esta forma usar el agente como una forma de comunicar información al usuario y que sea capaz de manera sencilla de ir hacia ella.

Ahora que ya tenemos creado nuestro agente, vamos a iniciarlo desde nuestra aplicación Windows Phone.

Vamos a crear un StackPanel con dos botones, uno para registrar el agente como una tarea periódica y otro como intensiva:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <StackPanel>
        <Button Name="btnPeriodic" Content="Tarea periódica"
                Click="btnPeriodic_Click"></Button>
        <Button Name="btnIntensive" Content="Tarea intensiva"
                Click="btnIntensive_Click"></Button>
    </StackPanel>
</Grid>

Primero vamos a añadir un using a nuestro agente y a Microsoft.Phone.Scheduler:

using Microsoft.Phone.Scheduler;
using BackgroundAgent;

En el manejador del evento click del botón periódico debemos incluir este código:

private void btnPeriodic_Click(object sender, RoutedEventArgs e)
{
    PeriodicTask tarea = (PeriodicTask)ScheduledActionService.Find("periodica");
    if (tarea == null)
    {
        tarea = new PeriodicTask("periodica");
        tarea.Description = "Tarea periódica";
        tarea.ExpirationTime = DateTime.Now.AddDays(10);
        ScheduledActionService.Add(tarea);
    }

    ScheduledActionService.LaunchForTest("periodica", new TimeSpan(0, 0, 20));
}

En el namespace Microsoft.Phone.Scheduler tenemos la clase SchedulerActionService que nos permite buscar tareas y lanzarlas bajo demanda para probarlas. Es importante no intentar crear dos veces una tarea con el mismo nombre pues el sistema fallará. También debemos tener cuidado con el método LaunchForTest, si intentamos enviar una aplicación al marketplace que use este método será rechazada automáticamente.

Una vez que hemos comprobado que no existe una tarea con el nombre que intentamos usar, podemos crearla, asignarle un nombre y una descripción y por último indicar el tiempo de expiración.

Si ejecutamos la aplicación y presionamos el botón “Tarea periódica” y salimos de la aplicación veremos que en 20 segundos aparecerá la notificación en el sistema:

image

Al pulsar sobre la notificación nos enviará a nuestra aplicación, usando para ello la uri que le hemos proporcionado. Esto es especialmente útil si hemos obtenido datos que deseamos mostrar al usuario, pudiendo enviarle directamente a la página de visualización.

Registrar una tarea intensiva es muy parecido e igual de sencillo. En este caso usaremos el objeto ResourceIntensiveTask:

private void btnIntensive_Click(object sender, RoutedEventArgs e)
{
    ResourceIntensiveTask tarea = (ResourceIntensiveTask)ScheduledActionService.Find("intensiva");
    if (tarea == null)
    {
        tarea = new ResourceIntensiveTask("intensiva");
        tarea.Description = "Tarea intensiva";
        tarea.ExpirationTime = DateTime.Now.AddDays(10);
        ScheduledActionService.Add(tarea);
    }

    ScheduledActionService.LaunchForTest("intensiva", new TimeSpan(0, 0, 20));
}

El resultado de la ejecución de la tarea es el mismo, aparentemente, que en el cado de la tarea recursiva, la diferencia radica en los puntos expresados anteriormente, sobre todo, el mayor tiempo de ejecución de la tarea y las restricciones de uso.

Tanto el objeto PeriodicTask como el ResourceIntensiveTask tienen una propiedad llamada BeginTime, esta viene dada por las clases base de las tareas programadas, pero no es usable en estos dos objetos y producirá una excepción si intentamos establecerla.

Conclusión

Aunque no son perfectas y todavía hay mucho espacio para la mejora, las tareas en segundo plano para Windows Phone 7.5 nos permiten crear nuevas formas de interactuar con el usuario y nos dan nuevas herramientas para realizar nuestras aplicaciones. Todas las restricciones a las que nos vemos sometidos en este sentido como desarrolladores tienen parte de justificación, aunque no del todo, en la comodidad del usuario, que no tenga que pelearse con un gestor de tareas complicado y que no vea afectado su rendimiento sin saber muy bien porqué, o la vida de su batería.

A continuación os dejo el código fuente del proyecto de ejemplo para que lo uséis a vuestro gusto.

Un saludo a todos, espero que os guste y Happy Coding!!

Un comentario sobre “Windows Phone 7.5: Tareas en segundo plano (2 de 2)”

Responder a anonymous Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *