[Windows 8] Apps Metro para desarrolladores Windows Phone 7.5 (3 de N)

Hola a todos!

En los artículos anteriores de la serie, hemos visto los fundamentos básicos para usar MVVM en una aplicación Metro: ViewModel Base, ViewModel Locator y Navegación. Hoy vamos a ver las particularidades del ciclo de vida de una aplicación Metro y lo parecido que este ciclo es al que tenemos en Windows Phone 7.5.

Ciclos de vida: Windows 8 vs Windows Phone 7.5

image

Como podemos observar en la comparación anterior, ambos sistemas comparten la misma base en su ciclo de vida: Una aplicación entra en ejecución, se suspende por una acción del usuario (cambio a otra aplicación, terminación, un fallo…) y una vez suspendida puede volver a entrar en ejecución por que el usuario la recupere o quedar indefinidamente en este estado hasta que el sistema decida terminarla por necesidades de rendimiento o cualquier otra consideración.

Sin embargo, si vemos los diagramas, Windows 8 parece ofrecer un ciclo de vida más simple (lo que no significa que sea menos potente o nos de menos opciones). Además, como añadido en Windows 8 la activación de nuestra aplicación puede venir dada por varios caminos, como veremos a continuación.

Estado: Activación

En Windows Phone nuestra aplicación podía ser Activada generalmente por dos vías: El usuario la lanzaba desde el tile de aplicación o volvíamos a ejecución después de estar en suspensión o en tombstoning.

En Windows 8, si el usuario lanza nuestra aplicación desde el tile de la misma o desde un tile de contenido (secundario), recibiremos el evento OnLaunched, situado en nuestro archivo app.xaml.cs:

Application OnLaunched
  1. protected override void OnLaunched(LaunchActivatedEventArgs args)
  2. {
  3.     // Create a Frame to act navigation context and navigate to the first page
  4.     var rootFrame = new Frame();
  5.     rootFrame.Navigate(typeof(BlankPage));
  6.  
  7.     // Place the frame in the current Window and ensure that it is active
  8.     Window.Current.Content = rootFrame;
  9.     Window.Current.Activate();
  10. }

Dentro de este evento se crea el Frame principal de nuestra aplicación, navegamos a nuestra página inicial y activamos la ventana principal. Además en el parámetro LaunchActivatedEventArgs podremos comprobar cual fue el estado anterior de ejecución de nuestra aplicación, de esta forma podemos comportarnos de diferente forma dependiendo de si la aplicación fue suspendida, terminada, cerrada por el usuario… todo esto a partir del enumerador ApplicationExecutionState:

Enum ApplicationExecutionState
  1. switch (args.PreviousExecutionState)
  2. {
  3.     case ApplicationExecutionState.ClosedByUser:
  4.     {
  5.  
  6.         break;
  7.     }
  8.     case ApplicationExecutionState.NotRunning:
  9.     {
  10.         break;
  11.     }
  12.     case ApplicationExecutionState.Running:
  13.     {
  14.         break;
  15.     }
  16.     case ApplicationExecutionState.Suspended:
  17.     {
  18.         break;
  19.     }
  20.     case ApplicationExecutionState.Terminated:
  21.     {
  22.         break;
  23.     }
  24. }

Pero Windows 8 ofrece nuevas formas de lanzar nuestra aplicación. Podemos responder a otros tipos de activación. Por poner un ejemplo, podemos indicar que el usuario puede buscar datos en nuestra aplicación, gestionar archivos y algunas otras opciones. Para estos casos especiales disponemos de Métodos de activación independientes que nos permitirán ejecutar la lógica necesaria:

Método Responde a…
OnSearchActivated Se lanza cuando la aplicación es iniciada desde la búsqueda del sistema operativo.
OnFileActivated Cuando se abre un archivo para cuyo tipo nos hemos registrado como que podemos abrirlo.
OnFileSavePickerActivated Si otra aplicación quiere guardar un archivo que podemos manejar, el usuario podrá escoger nuestra aplicación como destino y recibiremos este evento
OnFileOpenPickerActivated Al igual que al guardar, también podemos indicar que pueden abrir archivos de nuestra aplicación y nos llamarán a través de este evento.
OnShareTargetActivated Si nuestra aplicación es capaz de compartir información a redes sociales, el usuario puede usarla desde otras aplicaciones y recibiremos este evento

En el código del App.xaml.cs podremos manejar el evento o eventos que deseemos:

Eventos de activación
  1. protected override void OnSearchActivated(SearchActivatedEventArgs args)
  2. {
  3.     base.OnSearchActivated(args);
  4. }
  5.  
  6. protected override void OnFileActivated(FileActivatedEventArgs args)
  7. {
  8.     base.OnFileActivated(args);
  9. }
  10.  
  11. protected override void OnFileSavePickerActivated(FileSavePickerActivatedEventArgs args)
  12. {
  13.     base.OnFileSavePickerActivated(args);
  14. }
  15.  
  16. protected override void OnFileOpenPickerActivated(FileOpenPickerActivatedEventArgs args)
  17. {
  18.     base.OnFileOpenPickerActivated(args);
  19. }
  20.  
  21. protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
  22. {
  23.     base.OnShareTargetActivated(args);
  24. }

En próximos artículos veremos como activar cada una de estas actividades y como responder a ellas. Ahora lo importante es saber que estos son posibles puntos de entrada a nuestra aplicación.

Forzar Suspensión y Reinicio

Antes de pasar a ver como trabajar con los eventos de Suspensión y Reinicio, es importante que sepamos como forzar su ejecución. En Visual Studio 11 Beta debemos mostrar la barra de Debug Location (View > Toolbars > Debug Location) donde tendremos botones específicos para Suspender y reiniciar nuestra aplicación:

Estado: Suspensión

De forma muy parecida a Windows Phone, el estado de suspensión de una aplicación en Windows 8 se establece siempre que la aplicación no está viéndose en pantalla. Cuando esto ocurra, podemos tener una oportunidad de preservar información manejando el evento Suspending de la clase App:

Evento Suspending
  1. public App()
  2. {
  3.     this.InitializeComponent();
  4.     App.Current.Suspending += OnSuspending;
  5. }

Una vez que recibamos la llamada al método que maneja el evento Suspending, dispondremos de un máximo de 5 segundos (tiempo de procesador, no real) para guardar nuestros datos de forma segura:

Manejador OnSuspending
  1. void OnSuspending(object sender, SuspendingEventArgs e)
  2. {
  3.     KeyValuePair<string, object> data = new KeyValuePair<string,object>(«Nombre», «yeray»);
  4.     if (!ApplicationData.Current.LocalSettings.Values.Contains(data))
  5.         ApplicationData.Current.LocalSettings.Values.Add(data);
  6. }

Dentro del parámetro SuspendingEventArgs podemos encontrar una propiedad llamada SuspendingOperation que contiene toda la información sobre la suspensión que se está llevando a cabo. Una propiedad interesante es la Deadline que nos indica la fecha / hora exacta en la que termina el tiempo que tenemos para guardar los datos.

Dentro de esta propiedad SuspendingOperation tenemos un método GetDeferral que nos permite obtener un objeto del tipo SuspendingDeferral, una vez obtenido podemos ejecutar nuestro código de guardado y llamar al método Completed de SuspendingDeferral para indicar al sistema que hemos terminado y puede continuar con la suspensión. Esto no evita que debamos cumplir con el Deadline indicado en SuspendingOperation:

Uso de GetDeferral()
  1. void OnSuspending(object sender, SuspendingEventArgs e)
  2. {
  3.     SuspendingDeferral def = e.SuspendingOperation.GetDeferral();
  4.  
  5.     KeyValuePair<string, object> data = new KeyValuePair<string,object>(«Nombre», «yeray»);
  6.     if (!ApplicationData.Current.LocalSettings.Values.Contains(data))
  7.         ApplicationData.Current.LocalSettings.Values.Add(data);
  8.  
  9.     def.Complete();
  10. }

 

NOTA: Además de todo esto hay algo más que debemos tener en cuenta: Windows 8 administrará su memoria para tener el mayor número de aplicaciones en suspensión posible, pero si necesita liberar memoria empezará por las aplicaciones que más gasten, sin tener en cuenta la antigüedad de las aplicaciones en suspensión, por esto es buena idea que intentemos guardar en el almacenamiento todo lo que podamos e intentar que nuestra aplicación en suspensión sea lo más liviana posible, para tener más oportunidades de permanecer en suspensión.

Visibilidad

Aunque no se trata de un estado de la aplicación, sí es una parte importante de su ciclo de vida. En Windows Phone una vez que el usuario sale de nuestra aplicación por cualquier motivo (sin cerrarla) recibimos de manera automática el evento Deactivated que correspondería al evento Suspending de Windows 8. Pero en Windows 8 esta operación puede tener un retraso de hasta 10 segundos, tiempo durante el cual nuestra aplicación sigue en ejecución aunque no esté visible. Si volvemos a nuestra aplicación durante este tiempo, no se llevará a cabo la suspensión y reinicio de la aplicación, en su lugar solo se cambiará la propiedad Visibility de la ventana principal.

Podemos controlar estos cambios de visibilidad manejando el evento VisibilityChanged de nuestra ventana principal, justo después de activarla (como podemos ver en la línea tres del siguiente código):

Manjeando VisibilityChanged
  1. Window.Current.Content = rootFrame;
  2. Window.Current.Activate();
  3. Window.Current.VisibilityChanged += Current_VisibilityChanged;

Una vez recibido el evento podemos realizar acciones dependiendo de si estamos ocultándonos o volviendo a ser visibles:

Manejador VisibilityChanged
  1. void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs e)
  2. {
  3.     if (e.Visible)
  4.         Text = «Application visible»;
  5.     else
  6.         Text = «Application hidden»;
  7. }

Estado: Reinicio

Una vez que nuestra aplicación esté suspendida pueden ocurrir dos cosas: que el usuario vuelva a activarla en algún momento o que, por necesidades del sistema, Windows 8 la termine y elimine completamente de memoria. En el primer caso, recibiremos el evento Resuming al que podemos subscribirnos para realizar acciones adicionales necesarias para volver a poner en funcionamiento nuestra aplicación:

Registro de eventos
  1. public App()
  2. {
  3.     this.InitializeComponent();
  4.     App.Current.Suspending += OnSuspending;
  5.     App.Current.Resuming += OnResuming;
  6. }

Una vez subscritos al evento, podremos cargar valores que hayamos guardado en el ApplicationData durante el evento Suspending:

Manejador OnResuming
  1. void OnResuming(object sender, object e)
  2. {
  3.     Text = ApplicationData.Current.LocalSettings.Values[«Nombre»].ToString();
  4. }

LocalSettings vs RoamingSettings

Antes de continuar con el último de los estados posibles, quiero dedicarle un poco de atención a unas propiedades nuevas y extremadamente interesantes de la clase ApplicationData en Windows 8: LocalSettings y RoamingSettings. Estas dos propiedades tienen el mismo funcionamiento exacto:

RoamingSettings
  1. ApplicationData.Current.RoamingSettings.Values.Add(data);
  2. Text = ApplicationData.Current.RoamingSettings.Values[«Nombre»].ToString();

¿Cual es su diferencia? Pues básicamente LocalSettings guarda la información en el dispositivo que estemos usando, mientras que RoamingSettings la almacena en la nube y su contenido será accesible por nuestra aplicación en otros dispositivos que usen el mismo LiveID que estamos usando en este. Con esta pequeña diferencia, podremos realizar aplicaciones que se sincronicen entre varios dispositivos.

Podemos subscribirnos al Evento DataChanged de la clase ApplicationData (línea 7) para que se nos notifique cuando los datos en roaming han cambiado y así obtener los nuevos valores:

Evento DataChanged
  1. public App()
  2. {
  3.     this.InitializeComponent();
  4.     App.Current.Suspending += OnSuspending;
  5.     App.Current.Resuming += OnResuming;
  6.  
  7.     ApplicationData.Current.DataChanged += Current_DataChanged;
  8. }
  9.  
  10. void Current_DataChanged(ApplicationData sender, object args)
  11. {
  12.     Text = sender.RoamingSettings.Values[«Nombre»].ToString();
  13. }

Ejemplo

Para terminar este artículo he creado un ejemplo que va añadiendo los distintos estados por los que transita a una colección y mostrando esta colección en una lista en pantalla para que podamos comprobar como afectan nuestras acciones al ciclo de vida de la aplicación:

image

 

Conclusión

Con este artículo hemos visto todo lo que el ciclo de vida de una aplicación Metro tiene que ofrecer y como se parece y se diferencia de lo aprendido en Windows Phone, aunque son muy parecidos, se aprecia el trabajo de Microsoft en darnos un ciclo de vida más potente y la capacidad de realizar Roaming de los datos de nuestra aplicación podrá marcar la diferencia… Ahora solo necesitamos que Windows Phone lo soporte también, para poder realizar aplicaciones en ambas plataformas que se sincronicen entre sí, teniendo una versión tablet  y una versión móvil que nos permitan interactuar sobre la misma información de maneras distintas. Como siempre os dejo el código del ejemplo aquí para que podáis jugar con el, nos vemos en el próximo artículo de la serie.

Un saludo y Happy Coding!

Deja un comentario

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