4.- Procesos
en segundo plano
En ocasiones querremos que
nuestra aplicación realice ciertas tareas a pesar de no estar siendo
usada por el usuario en ese momento, como actualizar contenido a
partir del obtenido de un servicio web. Para ello Windows Phone (WP
en adelante) nos proporciona los ScheduledTask, tareas que se
ejecutarán en background.
Existen dos tipos
de ScheduledTask a nuestra disposicion: PeriodicTask y
ResourceIntensiveTask. El primero es una pequeña tarea que se
ejecuta periodicamente mientras que el segundo es una tarea de mayor
peso, que consume una gran cantidad de recursos del sistema y que se
ejecuta una sola vez y por más tiempo. Aunque nuestra aplicación
solo puede registrar una tarea en segundo plano, puede registrarla
para que sea de los dos tipos. Ambos tipos comparten una serie
de características o restricciones impuestas por el sistema. De este
modo WP se asegura de que ningun ScheduledTask entorpezca el uso del
dispositivo por parte del usuario o el desempeño de otros
ScheduledTasks:
- API limitada. El conjunto de APIs del sistema a la que puede acceder un ScheduledTask es menor comparado con el que puede acceder una aplicación. Siga el siguiente enlace para ver exactamente a que partes puede o no acceder un ScheduledTask: API disponible.
- Memoria limitada. La cantidad de memoria a nuestra disposición se recorta para que nuestro ScheduledTask no consuma tanta memoria que otras tareas (en primer o segundo plano) no tengan suficiente memoria como para ejecutarse correctamente. En dispositivos con una memoria de 1GB o mayor, el limite es de 25MB. En dispositivos con menos de 1GB el límite es de 11MB.
- Replanificación cada dos semanas. Aunque podemos especificar el tiempo que nuestra tarea estará planificada para su ejecución, este tiempo nunca puede exceder dos semanas. Esto significa que para que nuestra tarea pueda estar planificada más tiempo nuestra aplicación debe añadirla a la planificación periodicamente.
- Eliminadas de la planificación tras dos fallos. Si nuestra tarea falla (debido a una excepción o a exceder el límite de memoria) dos veces consecutivas el sistema la eliminará de la planificación. Nuestra aplicación deberá añadirla de nuevo para que pueda volver a ejecutarse.
Además de estas
características comunes cada tipo de ScheduledTask tiene sus propias
restricciones. Algunas pueden resultar demasiado limitadoras, pero su
objetivo es el de un mejor desempeño global del sistema.
En el caso de
ResourceIntensiveTask podemos ver que las restricciones nos indican
que este tipo está destinado para tareas de gran concumo como la de
actualización del sistema:
- Duración máxima de 10 minutos.
- El dispositivo debe estar conectado a una fuente de alimentación
- El dispositivo no puede estar conectado a a red a través de un servicio telefónico de datos.
- La capacidad de la batería del dispositivo debe estar como mínimo al 90%.
- El dispositivo debe estar en modo pantalla bloqueada.
- No puede ejecutarse si se está llevando a cabo una llamada telefónica
Para el caso de
PeriodicTask:
- Se ejecutarán en intervalos de 30 minutos.
- Duración máxima aproximada de 25 segundos.
- El modo de "ahorro de energía" puede impedir que nuestra tarea se ejecute.
- Cantidad de tareas planificadas limitada. Este límite puede cambiarse por el usuario pero debe ser como mínimo de seis.
Algunas de estas
restricciones pueden esquivarse en las versiones de desarrollo de
nuestra aplicación, para así poder probar y depurar nuestras
ScheduledTask sin problemas.
4.1.- Ejemplo de uso:
ScheduledTask (PeriodicTask)
Aunque el siguiente
ejemplo será el de un PeriodicTask, el uso de un
ResourceIntensiveTask es idéntico. Lo único que cambia es como el
sistema gestionará y ejecutará nuestro ScheduledTask, siguiendo las
restricciones antes explicadas.
Crearemos primero la App
clickando en el menú File -> Add -> New Project...
Ahora seleccionamos al final del todo Windows Phone Scheduled Task
Agent, le damos un nombre
(MySchedTask por ejemplo) y confirmamos. Se habrá creado
automaticamente un proyecto llamado MySchedTask y dentro de él un
archivo ScheduledAgent.cs. Dentro de este archivo veremos una clase
llamada ScheduledAgent, con un método llamdo OnInvoke(ScheduledTask
task), donde añadiremos el
código de nuestra tarea:
protected override void OnInvoke(ScheduledTask task)
{
//Podemos registrar nuestro task para que sea de los dos tipos distintos y comprobar aqui con que tipo
//concreto ha sido lanzado.
if (task is PeriodicTask){
// ...
}else{
// ...
}
// ...
if (exito){
NotifyComplete();
}else{
Abort();
}
}
El
método OnInvoke debe llamar al final a una de las funciones que
vemos en el último if-else. Si ha tenido exito y ha completado su
tarea en esta ejecución llamará a NotifyComplete(). En caso
contrario (algo le ha impedido llevar a cabo su tarea) a Abort().
A
continuación editamos el WMAppManifest.xml
para incluir nuestra nueva tarea y que sea reconocida por el sistema:
<Tasks>
<!-- Esta es la tarea de la página principal de nuestra aplicación -->
<DefaultTask Name="_default" NavigationPage="MainPage.xaml"/>
<!-- Esto es lo que debemos añadir para incluir nuestra nueva tarea -->
<ExtendedTask Name="BackgroundTask">
<BackgroundServiceAgent Specifier="ScheduledTaskAgent"
Name="MySchedTask"
Source="MySchedTask"
Type="MySchedTask.ScheduledAgent"/>
</ExtendedTask>
</Tasks>
Ahora
ya solo queda modificar nuestra aplicación para que lance nuestro
ScheduledTask. En el SolutionExplorer de Visual Studio hacemos click
en el proyecto de nuestra aplicación y a continuación en el menú
Project -> Add Reference...
Seleccionamos la pestaña Projects
y elegimos el proyecto de nuestro ScheduledTask (MySchedTask).
En el
código de nuestra aplicación crearemos una función llamada
StartTask() que añadirá el ScheduledTask a la planificación de
tareas del sistema. Hay que tener en cuenta que si la tarea ya se
encuentra ahí no hay manera de actualizarla. Deberemos eliminarla y
añadirla de nuevo.
private void StartTask()
{
String periodicTaskName = "PeriodicAgent"
// Si la tarea ya se encuentra en ScheduledActionService la eliminamos
periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;
if (periodicTask != null){
try{
ScheduledActionService.Remove(periodicTaskName);
}catch (Exception){
}
}
//Creamos la tarea
periodicTask = new PeriodicTask(periodicTaskName);
// Le añadimos una descripción que será la que el usuario vea en la pantalla de procesos en segundo plano
// en Preferencias
periodicTask.Description = "Esta es mi pequeña tarea. En el fondo no hace nada :(";
try{
// Añadimos nuestra tarea a la planificación
ScheduledActionService.Add(periodicTask);
PeriodicStackPanel.DataContext = periodicTask;
}catch (InvalidOperationException exception){
// En caso de que el usuario tenga desactivada la opción de procesos en segundo plano...
if (exception.Message.Contains("BNS Error: The action is disabled")){
MessageBox.Show("El usuario no me deja ejecutarme. El se lo pierde...");
// ...
}
// En caso de que el límite de procesos en segundo plano haya sido excedido...
if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added.")){
// ...
}
}catch (SchedulerServiceException){
// ...
}
}
Con
esto ya tendremos una tarea planificable y ejecutable.
Por
último veremos como podemos lanzar la tarea siempre que queramos,
esquivando como dije antes algunas de las restricciones:
ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60));
5.- Conclusiones
Hemos visto el lanzamiento de procesos de distintos tipos. Aunque aún falta profundizar más en ciertos detalles la línea general es que en WP es insultantemente fácil usarlos. Quizá la asociación de URIs pueda parecer más engorrosa, pero en la práctica y usando alguna biblioteca de soporte (para parsear) creo que se convierte en un método muy sencillo e intuitivo de integrar otras aplicaciones. La única nota negativa quizá la dan los procesos en segundo plano, que imponen una serie de restricciones demasiado desalentadoras.
Referencias
No hay comentarios:
Publicar un comentario