Compartir a través de


Asuntos móviles

Extinción de Windows Phone 7

Jaime Rodríguez

Descargar el ejemplo de código

Una buena plataforma móvil debe reconocer las restricciones de hardware que la movilidad impone sobre el dispositivo. En comparación con los equipos de escritorio, los dispositivos móviles tienen menos memoria, menor eficacia de procesamiento, un estado real de pantalla limitado y una duración limitada de la batería. Sume estas restricciones y concluirá que, en un dispositivo no dedicado donde se ejecutarán varias aplicaciones, a la larga las aplicaciones se deberán cerrar para que haya recursos disponibles para otras aplicaciones.

Windows Phone enfrenta esta restricción a través de una característica llamada extinción. A pesar de que extinción pudiera sonar como una propuesta directa, en realidad es un punto de contención entre los desarrolladores. Algunos plantean que no debiera ser necesaria. Otros plantean que es demasiado complicada. El resto simplemente odiamos el nombre de la característica. Incluso así, las restricciones de dispositivos móviles la convierten en un mal necesario, por lo que las buenas aplicaciones móviles deben ser capaces de administrar la extinción.

Ciclo de vida de las aplicaciones de Windows Phone

La mayoría de los desarrolladores de Windows Phone llegan a la plataforma con la expectativa de que el ciclo de vida de una aplicación se vea similar a: 

  1. Inicio
  2. Ejecutar
  3. Salir
  4. Vuelva a 1 y empiece nuevamente

Windows Phone 7 desafía esta expectativa al exponer un ciclo de vida distinto, uno que está menos orientado al proceso y más orientado a las sesiones.

En Windows Phone 7, podría considerar al ciclo de vida como:

  1. Inicio
  2. Ejecutar
  3. Ejecución interrumpida o terminada
  4. Si se interrumpe, vuelva o, incluso si se interrumpe, comience de nuevo
  5. Si se termina, comience de nuevo 

El beneficio de este nuevo modelo orientado a las sesiones es que los usuarios pueden navegar entre las aplicaciones sin tener que pensar cómo el sistema operativo administra sus recursos. Al usuario no le interesa saber si interrumpir el juego para responder un mensaje SMS entrante terminará el proceso del juego. El usuario esperará poder volver al juego una vez que termine de leer el mensaje. Si eso funciona bien, los detalles subyacentes no resultan importantes.

La desventaja para los desarrolladores es que hay un poco más que controlar para brindar realmente la percepción de la continuidad de la sesión, dado que las sesiones siguen en ejecución en un sistema operativo tradicional y centrado en los procesos. Para ajustar las sesiones en un mundo centrado en los procesos, puede crear estados lógicos para la sesión: Iniciado, Activado, En ejecución, Desactivado, Extinto y Cerrado (o Finalizado).

La figura 1 muestra el ciclo de vida práctico para una aplicación de Windows Phone 7. Los eventos del ciclo de vida de la aplicación, descritos en la figura 2, son expuestos por la clase Microsoft.Phone.Shell.PhoneApplicationService. 

Windows Phone 7 Application Lifecycle

Figura 1 Ciclo de vida de aplicaciones de Windows Phone 7

Figura 2 Eventos del ciclo de vida de aplicaciones

Estado lógico Evento PhoneApplicationService Descripción
Iniciado Inicio La aplicación se inicia cuando el usuario presiona el mosaico de inicio o el icono de la lista de aplicaciones, o el usuario hace clic en una notificación de aviso. “Iniciado” es un inicio nuevo de la sesión.
Activado Activado La aplicación se activa cuando el usuario presiona el botón Atrás y trae al primer plano la aplicación que se ha desactivado anteriormente. En este caso, el usuario espera volver a una sesión en curso.
En ejecución En ejecución Una vez que se ha iniciado o activado, la aplicación está en ejecución. 
Desactivado Desactivado Una aplicación que está en ejecución se desactiva cuando el procesamiento en primer plano se transfiere desde su aplicación a otra aplicación o a un componente de sistema operativo(como un Selector o un Iniciador o la pantalla de bloqueo). La sesión se interrumpe, pero se espera reanudar más adelante.
Finalizado (o Terminado) Cierre

El usuario sale de la aplicación al presionar la tecla atrás en la página principal.

Una vez que sale, el usuario espera volver a una aplicación nueva y actualizada.

El estado extinto es un poco más complicado y no está directamente relacionado con un evento PhoneApplicationService. Cuando una aplicación se desactiva, el sistema operativo no termina inmediatamente el proceso de esa aplicación. En teoría, el sistema operativo termina la aplicación cuando necesita recursos y, cuando esto ocurre, la aplicación no recibe ninguna notificación, sino que simplemente se termina.  

En la práctica, Windows Phone 7 termina el proceso rápidamente una vez que el control se transfiere a otra aplicación en primer plano, pero este no es un detalle con el que debiera contar. Microsoft ya anunció en el Congreso mundial móvil de febrero pasado futuras mejoras, como Cambio rápido de aplicaciones, por lo tanto, no se base en un detalle de la implementación para determinar cuándo se produce la extinción. En lugar de eso, prepárese para la extinción haciendo el trabajo adecuado en la desactivación.

Desactivación frente a extinción

Un teléfono tiene muchos procesos en ejecución a cada momento (shell, teléfono, etc.) pero tiene, como máximo, una aplicación en ejecución en primer plano. (Puede no tener ninguna si no hay una aplicación ejecutándose en primer plano).

Cuando una aplicación en primer plano transfiere el control a otra aplicación o a un componente de sistema operativo, se desactiva. Cuando se desactiva un proceso, el sistema operativo puede terminar el proceso para liberar los recursos. Esta acción se llama extinción. 

Como puede ver, la extinción no ocurre cada vez que se desactiva la aplicación, pero sí ocurre siempre después de una desactivación. De hecho, Desactivado es el último evento que PhoneApplicationService activa antes de la extinción, por lo tanto, es aquí donde debe trabajar para activar nuevamente la aplicación más adelante.

La figura 3 muestra todas las tareas distintas que llevan a la desactivación y realiza una estimación de la probabilidad de que se produzca una extinción. 

Figura 3 Tareas de desactivación

Acción ¿Desactivado? ¿Extinto?
El usuario presiona el botón Atrás en la primera página de la aplicación. No; con esto se cierra la aplicación. No; la desactivación nunca ocurrió.
El usuario presiona el botón Inicio Muy probable, pero no garantizado. Unos pocos segundos después de desactivar la aplicación, se extingue. Si el usuario vuelve rápidamente a la aplicación después de la desactivación, no se extinguirá. Esto podría considerarse como un tiempo de expiración indeterminado.
El usuario invoca un selector o un iniciador que se extingue Muy probable, pero se aplica tiempo de expiración.
El usuario invoca un selector o un iniciador que no se extingue Menos probable, pero puede pasar. Si el usuario presiona el botón Inicio en medio de la tarea, verá la regla “El usuario presiona el botón Inicio”. No se activa un nuevo evento Desactivado, porque la aplicación ya estaba desactivada. 
Aparece la pantalla de bloqueo y la aplicación no está configurada para ejecutarse en modo de bloqueo Muy probable, pero se aplica tiempo de expiración.
Aparece una notificación de aviso y el usuario la toca suavemente, transfiriéndola a otra aplicación en primer plano Muy probable, pero se aplica tiempo de expiración.

Hay un subconjunto de selectores que no se extinguen de inmediato, pero que se pueden extinguir si el usuario realiza una acción que extinga el proceso. Estas acciones incluyen PhotoChooserTask (a menos que el usuario especifique el recorte), CameraCaptureTask, MediaPlayerLauncher, EmailAddressChooserTask y PhoneNumberChooserTask.

Todos los demás selectores e iniciadores se extinguen una vez que se llama al método Show.

Para ver en acción el ciclo de vida de aplicaciones de Windows Phone 7, inicie la muestra LWP.TombStoning que aparece en la descarga del código. 

Guardado y restauración del estado

Como el objetivo de la navegación basada en sesión es facilitar que el usuario alterne sin problemas entre las aplicaciones de primer plano, debe guardar todo estado pertinente en el evento Desactivado y restaurar el estado en el evento Activado. La mayoría de las aplicaciones tienen tres tipos de estado que administrar:

  • El estado de aplicación persistente siempre se debe conservar. Esto incluye la configuración de la aplicación, los datos del usuario, etc.
  • El estado de la aplicación específica de sesión incluye un estado temporal como memorias caché y ViewModels que se deben restaurar en la activación, pero que se iniciaron de nuevo en un inicio nuevo de la aplicación.
  • El estado específico de UI o de página es necesario para restaurar un PhoneApplicationPage cuando se activa una aplicación. Windows Phone 7 guarda la pila de retroceso de una aplicación cuando se extingue. Después de la activación, restaura solo la última página activa antes de que se extinguiera la aplicación. Si el usuario presiona el botón Atrás, se inicia la página anterior.

El estado de aplicación persistente se debe guardar en IsolatedStorage o a través de la clase ApplicationSettings. El estado de aplicación se debe guardar lo antes posible, por ejemplo, en caso de que la batería se agote. 

Si son datos de usuario (como una memoria caché de sesión) y no desea serializar con demasiada frecuencia, debieran guardarse tanto en el evento Desactivado como en el de Cierre y (de manera simétrica), se debieran restaurar en los eventos Activado o de Inicio.

El estado específico de sesión se puede guardar en un almacenamiento aislado si desea tener el control sobre los formatos de serialización o si tiene demasiados datos, o se pueden guardar en el diccionario PhoneApplicationService.State. Debiera guardarlo solo en el evento Desactivado y restaurarlo en el evento Activado.

El estado específico de página debiera guardarse en el diccionario PhoneApplicationPage.State. La clave para guardar el estado de página es recordar que la aplicación tiene una pila de retroceso de páginas que se serializarán automáticamente cuando se produzca el PhoneApplicationService.Deactivated. Para mantener las páginas listas para extinción, debe escuchar el reemplazo de PhoneApplicationPage.OnNavigatedFrom en la página y guardar cualquier estado de vista que todavía no se haya confirmado en el modelo (o ViewModel) en el diccionario de la página. No espere hasta el evento Desactivado, porque entonces no podrá alcanzar las páginas en la pila de retroceso.

Por supuesto, si guardar el estado de página cuando recibe OnNavigatedFrom, debiera restaurarlo en el reemplazo de OnNavigatedTo para la página.

También podría guardar el estado específico de página en ViewModels y luego serializar su ViewModels como estado de sesión, pero eso requeriría guardar un estado no confirmado en un ViewModel, por lo que no lo recomiendo. Use la infraestructura disponible para mantenerse disponible para optimizaciones posteriores de la plataforma.

Eliminación de riesgos

La extinción no es difícil. Es un trabajo algo tedioso y exige coherencia y planeación. Si la aplicación se desactiva pero no se extingue, su estado seguirá en la memoria y no se reconstruirá. 

Evita basarse en constructores de clase que crean un estado necesario para su aplicación, pero que se pueda liberar durante la desactivación. Se prefiere la simetría. Use los eventos Desactivado y Activado de PhoneApplicationService para el estado en el nivel de la aplicación y OnNavigatedFrom u OnNavigatedTo para el estado de la página. 

Si tiene objetos (singletons) en la aplicación con instancias que se crean fuera de las llamadas de activación (probablemente debido a una creación de instancia con retraso), compruebe siempre si están construidos y se inicializan correctamente antes de intentar usarlos. Un error común que he encontrado es leer datos en el evento PhoneApplicationService.Activated o en PhoneApplicationPage.OnNavigatedTo y no restablecerlos. Las páginas se pueden NavigatedTo varias veces (independientemente de la extinción) e incluso una sesión se puede extinguir varias veces durante una sesión.

Una vez que ha restaurado el estado, elimínelo. Puede definirlo más tarde en el reemplazo de NavigatedFrom para su página o en el evento Desactivado de la aplicación.

Sepa qué guarda y cuándo restaurarlo. Restaurar oportunamente la aplicación es parte de hacer que sea fácil que el usuario vuelva a la aplicación. Si guarda muchos datos de cualquier estado de aplicación o página, la activación se demorará. Aproveche el almacenamiento aislado si es necesario poner en segundo plano el estado de carga que pudiera no ser necesario inmediatamente cuando se activa la aplicación. Tanto la activación como la desactivación debieran ocurrir en menos de 10 segundos. Tenga en cuenta esto o el sistema operativo podría terminar el proceso antes de finalizar la desactivación o cuando se reactive. Sin embargo, debiera apuntar a mucho menos de 10 segundos.

Comprenda las restricciones del marco de serialización. Como máximo, puede almacenar alrededor de 2 MB en todo el estado de aplicación y la página. Si el total suma más, comenzará a ver excepciones cuando navega y cuando hace la desactivación. No debiera serializar esta cantidad de datos en el estado de página. Si necesita almacenar en caché conjuntos de datos de gran tamaño, manténgalos en un almacenamiento aislado.

Use cadenas de consulta para la navegación de páginas. Si debe pasar contexto a una página nueva, use la cadena de consulta pasada a la página para pasar todos los datos o solo un identificador único (un token) a un localizador de servicios que puede buscar los datos basándose en ese token. No piense que ViewModels o el estado de página estarán disponibles cuando las páginas se activan después de la extinción.

Conozca los selectores e iniciadores. No todos ellos se extinguen, y hay reglas específicas sobre cómo conectar escuchas de eventos para los selectores. Para conocer estas reglas, lea “Procedimientos: Uso de selectores para Windows Phone” en bit.ly/edEsGQ.

Tenga presente la relación entre OnNavigatedTo y PhoneApplicationPage.Loaded. Dentro de OnNavigatedTo, el árbol visual de la página todavía no está completamente construido. A menudo, deberá extraer el estado restaurado, pero espere a que el evento Cargado de la página restaure el estado de UI. Los ejemplos de las acciones que se deben retrasar incluyen el Enfoque, la definición de SelectedIndex en un control dinámico y un desplazamiento.

Si tiene muchos datos que guardar y restaurar, y no debiera, considere algunas optimizaciones avanzadas. Observe que debe hacer esto solo si es necesario y asegúrese de realizar pruebas exhaustivas.

Para detectar extinciones, establezca una marca en su clase de aplicación en Desactivado. Si la marca no se restablece en Activado, significa que no estaba extinto y que todas sus páginas debieran estar todavía en la memoria y que no necesitan restauración. Para combinarla con la detección de extinción en las páginas, puede usar un token para cada activación dentro de una sesión.

Otra optimización es escuchar el reemplazo de OnNavigatingFrom de la página y detectar la dirección. Si NavigationMode retrocede, la página se destruirá y no habrá motivo para guardar su estado.

Nuevamente, la planeación resulta clave para realizar una extinción adecuada. No deje la extinción para el final del ciclo de desarrollo de la aplicación ni intente ajustarla retroactivamente. Planéela en una etapa temprana, impleméntela cuando esté en el proceso y realice pruebas exhaustivas. 

Puede hacerlo muy bien

Una última sugerencia para los desarrolladores es pensar muy bien respecto de hacer que la experiencia no presente inconvenientes. Los controles de Windows Phone 7 le permiten evitar fácilmente una página. Para hacerlo realmente sin inconvenientes para el usuario, para que así sientan que nunca han salido de una página o de una aplicación, debiera considerar la restauración de los siguientes elementos:

  • SelectedIndex para el control dinámico (si la página contiene un control dinámico)
  • La posición de desplazamiento en un ListBox o en cualquier otro ScrollViewer en la página
  • Niveles de zoom y otras transformaciones en un control de mapa, visor de imágenes o cualquier otro control que admite manipulación
  • Texto no confirmado en un TextBox; si el TextBox es crítico para la aplicación (el texto de los mensajes en una aplicación de Twitter, por ejemplo) considere restaurar la selección de texto, la posición del símbolo de intercalación y el enfoque
  • Elemento que tenía enfoque en una página (especialmente si es un TextBox, que necesita mostrar SIP)

Lo que no puede restaurar es SelectedItem en una panorámica. La panorámica no admite esta acción, y la definición del DefaultItem en una panorámica no es igual que un movimiento panorámico en la página correcta. Recomiendo evitar el uso de DefaultItem como un medio de obtener el elemento panorámico seleccionado antes de la extinción.

Para ver en acción estas sugerencias, inicie la muestra de LPW.TombstoningWithState en la descarga del código. El archivo léame.txt tiene punteros y scripts para cada escenario.

Unos últimos comentarios

Este artículo en ningún caso representa una referencia integral de la extinción. Pero ahora que sabe lo que debe observar, comience a introducir algunos patrones de extinción en sus propias aplicaciones de Windows Phone 7. Creo que verá inmediatamente cuánto se mejora la experiencia del usuario.

Jaime Rodríguez es experto de Microsoft para la dirección de la adopción de tecnologías de cliente emergentes como Silverlight y Windows Phone 7. Puede ponerse en contacto con él en Twitter en su cuenta twitter.com/jaimerodriguez o lea su blog en blogs.msdn.com/jaimer.

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Peter Torr