Windows Phone 8 Tip: Fast App Resume

Hola a todos!

Hoy vengo con un pequeño truco, que mejorará increíblemente la experiencia de uso de nuestra aplicación. Se trata de una nueva característica de Windows Phone 8 llamada Fast App Resume.

Pero… ¿Qué es esto exactamente? Bueno, desde Windows Phone 7.5, sabemos que nuestra aplicación queda suspendida cuando el usuario va a la pantalla inicial. Si presionamos el botón atrás durante unos segundos, aparece el gestor de aplicaciones, donde vemos todas las aplicaciones abiertas (y suspendidas) en ese momento, podemos pulsar sobre una y automáticamente se vuelve a activar. Esto es lo que conocemos como FAS, Fast Application Switching. Pero si, en vez de usar este método, el usuario vuelve a pulsar sobre el icono de la aplicación o el Tile, la instancia suspendida es eliminada de memoria y se crea una nueva instancia. Esto, por supuesto, es mucho más lento que recuperar una instancia ya creada. Para solventar este inconveniente, Windows Phone 8 soporta además de FAS, un nuevo modo llamado FAR, Fast Application Resume. FAR nos permite indicar al sistema que deseamos mantener la instancia actualmente creada aunque el usuario pulse sobre el Tile principal de la aplicación. De esta forma solo se tiene que activar la instancia y no destruirla y crearla de nuevo. Por supuesto esto es muchísimo más rápido. Si estás mirando que características añadir a una aplicación migrada desde Windows Phone 7.5 a 8.0, esta es indispensable.

FAR: Fast Application Resume

¿Y como lo activamos? Aquí viene la mejor parte, solo tenemos que modificar una línea del XML del manifiesto de nuestra aplicación para activarlo. Tenemos que buscar el elemento DefaultTask y añadirle el atributo ActivationPolicy:

<Tasks>
  <DefaultTask  Name ="_default" NavigationPage="MainPage.xaml" ActivationPolicy="Resume"/>
</Tasks>

Este atributo ActivationPolicy puede recibir dos valores: Resume o Replace. Resume activa el Fast Application Resume, indicando que siempre que sea posible la aplicación debe recuperar la instancia activa. Replace es el valor por defecto si no indicamos Resume y genera el comportamiento normal, la aplicación inicia una nueva instancia.

¿Como podemos comprobar la diferencia entre ambos modos? Podemos verlo de forma muy sencilla que nos ilustrará los efectos del FAR. Vamos a crear una aplicación Windows Phone 8 que tenga un TextBox en su página principal. Sin indicar el valor del ActivationPolicy, hagamos los siguiente pasos:

  1. Desplegamos en el dispositivo o emulador.
  2. Escribimos “Hola app” en el TextBox.
  3. Presionamos el botón inicio.
  4. Vamos a la lista de aplicaciones y pinchamos de nuevo sobre nuestra aplicación.

¿Cuál es el resultado? El texto “Hola app” ha desaparecido, bueno, en realidad nunca estuvo escrito, puesto que al pinchar sobre la aplicación, se ha destruido la instancia suspendida (donde estaba el texto) y se ha creado una nueva. Vamos a repetir la prueba, solo que ahora, modificaremos nuestro manifiesto para añadir el atributo ActivationPolicy=”Resume”. ¿Cual es el resultado? Efectivamente, el texto permanece en su sitio, puesto que lo que hemos realizado es recuperar la copia en memoria.

Cambios en la navegación

Aunque, como hemos visto, implementar FAR es muy sencillo y sus ventajas son obvias, queda un asunto por discutir: la navegación. ¿Qué experiencia de navegación deseamos ofrecer al usuario? Dependiendo de como activemos la aplicación, cambiará la experiencia de navegación que obtendremos:

  • Si activamos la aplicación desde un tile o desde la lista de aplicaciones: Se reiniciará la pila de navegación y a continuación se realizará una navegación a la página que corresponda.
  • Si volvemos al la aplicación con el botón atrás o desde la lista de apps abiertas: Volveremos a la página abierta, conservando la pila de navegación.

Esta diferencia se da debido a que, al navegar desde un tile o la lista de aplicaciones, recibimos dos navegaciones. La primera de ellas va dirigida a la página principal de nuestra aplicación con el modo de navegación establecido en Reset. Este modo es manejado por el método CheckForResetNavigation de la clase App (App.xaml.cs) y se encarga de limpiar la pila de navegación:

private void CheckForResetNavigation(object sender, NavigationEventArgs e)
{
    // If the app has received a 'reset' navigation, then we need to check
    // on the next navigation to see if the page stack should be reset
    if (e.NavigationMode == NavigationMode.Reset)
        RootFrame.Navigated += ClearBackStackAfterReset;
}

private void ClearBackStackAfterReset(object sender, NavigationEventArgs e)
{
    // Unregister the event so it doesn't get called again
    RootFrame.Navigated -= ClearBackStackAfterReset;

    // Only clear the stack for 'new' (forward) and 'refresh' navigations
    if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh)
        return;

    // For UI consistency, clear the entire page stack
    while (RootFrame.RemoveBackEntry() != null)
    {
        ; // do nothing
    }
}

A continuación recibimos una segunda navegación, esta vez a la página que deseamos llegar y con el modo establecido en New. De esta forma, aunque hemos recuperado la instancia activa de la aplicación, que es mucho más rápido que abrir una nueva, tenemos la impresión de estar ante una nueva instancia. Pero puede ocurrir que deseemos ofrecer una experiencia diferente al usuario, haciendo que al pulsar un tile principal o la lista de aplicaciones, vuelva a la página activa antes de suspender la aplicación. Para esto tendremos que controlar la forma en la que se está iniciando la aplicación. Sabemos que en el evento CheckForResetNavigation un modo de Reset significa que se inicia desde un tile o lista de aplicación y que a continuación navegará a la página indicada, poniéndola encima del resto en la pila de navegación. podríamos modificar el CheckForResetNavigation para hacer algo parecido a esto:

private bool loadingfromInstance = false;

private void CheckForResetNavigation(object sender, NavigationEventArgs e)
{
    if (e.NavigationMode == NavigationMode.New && this.loadingfromInstance)
        RootFrame.GoBack();

    // If the app has received a 'reset' navigation, then we need to check
    // on the next navigation to see if the page stack should be reset
    if (e.NavigationMode == NavigationMode.Reset)
        this.loadingfromInstance = true;
}

De esta forma, en la primera navegación con el modo Reset, no eliminamos la pila de navegación y marcamos a true la variable loadingFromInstance. En la segunda navegación, con el modo New, controlamos que previamente hayamos recibido un Reset. Si es así, navegamos atrás, para volver a la página en la que dejamos la aplicación. De cara al usuario, el resultado es recuperar la aplicación en el mismo punto exacto en que la dejó y con la misma pila de navegación. Un ejemplo de este comportamiento lo tenemos en la aplicación de Facebook para Windows Phone 8, que se comporta exactamente de esta manera.

Pero con este código, veremos que tenemos un inconveniente. Primero se carga la página principal y a continuación se navega hacia atrás y se muestra la página en la que nos encontrábamos, haciendo un efecto bastante feo. Para arreglar esto, debemos modificar el método InitializePhoneApplication para añadir un manejador al evento Navigating del objeto RootFrame. En este manejador, comprobaremos si estamos navegando a la página principal y si loadingFromInstance es true. Si se cumplen ambas condiciones, cancelaremos la navegación.

Es importante que volvamos a establecer loadingFromInstance a false una vez que realicemos este paso o cualquier tipo de navegación a la página principal será cancelada:

void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e)
{
    if (e.Uri.ToString().Contains("MainPage.xaml") && this.loadingfromInstance)
    {
        e.Cancel = true;
        this.loadingfromInstance = false;
    }
}

De esta forma, no necesitamos hacer el GoBack en nuestro método CheckForResetNavigation, simplemente no navegamos a la página principal si estamos recuperando la instancia, quedando el código de ese método mucho más sencillo como podemos ver a continuación:

private bool loadingfromInstance = false;

private void CheckForResetNavigation(object sender, NavigationEventArgs e)
{
    if (e.NavigationMode == NavigationMode.Reset)
        this.loadingfromInstance = true;
}

Y Voila! Ya tenemos nuestra aplicación recuperando la instancia anterior y dejando al usuario en el mismo sitio exacto en el que estaba.

Conclusión

El FAR o Fast Application Resume en Windows Phone 8 es una de las novedades más útiles y a la vez más pasada por alto que nos ofrece la nueva versión del sistema operativo. Podemos ofrecer al usuario una experiencia de recuperación de estado mucho mejor y una velocidad de inicio de nuestra aplicación mayor, usando este simple truco. En nuestras manos queda como manejar la pila de navegación, si queremos ofrecer una experiencia de continuidad o simplemente aprovecharnos de la rapidez de inicio y reiniciar la navegación para que se asemeje a un arranque desde cero.

Como siempre, a continuación os dejo un pequeño ejemplo del uso de FAR, con una aplicación que contiene dos páginas y nos permite crear un tile secundario para probar la navegación desde diferentes puntos.

Un saludo y Happy Coding!

4 comentarios sobre “Windows Phone 8 Tip: Fast App Resume”

Responder a anonymous Cancelar respuesta

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