Optimizing the Resume Experience

,

Fast App Resume in your app should be implemented in a manner that ensures a predictable experience for the user. The behavior of your app when it is resumed should depend on the entry point of your app when it was initially launched from a cold start and the entry point when it was resumed.

There are two kinds of entry points. Primary entry points occur via a primary tile on the Start Experience or an app link in the App List or Games hub. Secondary entry points occur via a deep link from a secondary tile, a toast notification, or from an extensibility point such as a protocol handler.

The Windows Phone OS maintains a navigation history for your app. When the user taps the hardware Back button, the OS navigates back through the stack of previously visited pages. With Fast App Resume the OS attempts to navigate to a URI within your app. If the URI is different from the current page of the app, a new page instance is created and placed on the navigation back stack. If the URI is identical to the app’s current location, no new page is created and the app’s current page is displayed.

If the entry point is your app’s primary tile, for example, the URI is your app’s main landing page. When an app is resumed via a primary entry point, it can respond in one of the following two ways:

Image It can start fresh by clearing the back stack and navigating to the app’s main landing page. If the user navigates backward from the resumed app, because there are no pages in the history the app will exit, returning the user to the Start Experience or the previous app.

Image It can resume as if nothing happened by canceling navigation to the requested URI. In this case, the user arrives on the page that he last viewed and the back stack from the previous session remains intact.

Although it is possible to resume as if nothing happened whenever the user launches your app from a primary entry point, after a few minutes of inactivity it is better to start fresh. The user may no longer be mindful of the app’s presence in the background and will expect that relaunching the app starts a new instance. In the sample for this section, you see how to detect and expire a Fast App Resume in this scenario.

Implementing Fast App Resume gets more complicated when the user launches or resumes an app from a secondary entry point. For example, if the user launches the app via its primary tile and then taps the hardware Start button, the app is deactivated and waits to be resumed. If the user then navigates to the Photo hub and relaunches the app from the picture viewer, the app should resume by clearing the back stack and navigating to the requested deep link URI.

Table 3.1 shows the recommended behavior for resuming via a primary or secondary launch point after being launched from either a primary or secondary entry point.

TABLE 3.1. Fast App Resume Recommended Resume Behavior

Image

An appropriate place for detecting and coordinating Fast App Resume is in your project’s App class. The App class in the WPUnleashed.Examples project, in the downloadable sample code, responds to the various Fast App Resume scenarios.

When the sample app is deactivated, the App class records the time of deactivation in the app’s isolated storage settings. When the app is activated, a field is set to the result of the HasFastResumeExpired method, which is shown in Listing 3.1.

Although it is not absolutely necessary for the purposes of Fast App Resume to store the deactivation time in isolated storage, it does allow the value to be used for other purposes in which tombstoning may occur.

LISTING 3.1. App.HasFastResumeExpired Method


bool HasFastResumeExpired()
{
    DateTimeOffset lastDeactivated;

    if (settings.Contains(DeactivationTimeKey))
    {
        lastDeactivated = (DateTimeOffset)settings[DeactivationTimeKey];
    }

    TimeSpan duration = DateTimeOffset.Now.Subtract(lastDeactivated);

    return TimeSpan.FromSeconds(duration.TotalSeconds)
                > fastResumeExpiryTime;
}


You saw earlier that an app can be launched or resumed via a primary or secondary entry point. The App class uses a custom enum named SessionType to record if the app is navigating to the app’s home page via a primary entry point or to a deep link URI via a secondary entry point. SessionType can be either None, Home, or DeepLink.

Each time a navigation event is raised, the App class’s RootFrame_Navigating handler determines the SessionType using the NavigatingCancelEventArgs object’s Uri property (see Listing 3.2). If the session type has not been recorded and the navigation mode is set to New, it indicates that the app is launching. When the navigation mode is equal to Reset, a Fast App Resume is underway.

During a Fast App Resume, if the current page URI is not the same as the requested URI, the root frame’s Navigating event is raised twice; once for the page that was displayed before deactivation and once for the requested URI. If the current page URI is the same as the requested URI, the Navigating event is raised only once for the page that was displayed before deactivation.

LISTING 3.2. App.RootFrame_Navigating Method


void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e)
{
    string url = e.Uri.ToString();

    if (sessionType == SessionType.None && e.NavigationMode == NavigationMode.New)
    {
        /* App is launching. */

        if (url.Contains("?"))
        {
            sessionType = SessionType.DeepLink;
        }
        else if (url.Contains("/MainPage.xaml"))
        {
            sessionType = SessionType.Home;
        }
    }

    if (e.NavigationMode == NavigationMode.Reset)
    {
        /* The current navigation is the result of a Fast App Resume.
            * If so the URI is different from the current page URI
            * then another navigation will follow. */
        lastNavigationWasReset = true;
    }
    else if (e.NavigationMode == NavigationMode.New && lastNavigationWasReset)
    {
            /* This block will run once if the previous navigation
            * was the result of a Fast App Resume. */
        lastNavigationWasReset = false;

        if (url.Contains("?"))
        {
                /* We reach this point if a secondary entry point was used,
                * such as via the secondary tile
                * created in FastAppResumeViewModel.cs */

            sessionType = SessionType.DeepLink;
            /* The page navigation stack will be cleared. */
        }
        else if (url.Contains("/MainPage.xaml"))
        {
            if (sessionType == SessionType.DeepLink)
            {
                /* When the app was previously launched via a deep link URI
                    * and relaunched via its primary tile,
                    * the back stack needs to be cleared. */
                sessionType = SessionType.Home;
            }
            else
            {
                if (!fastResumeExpired)
                {
                    /* The app was previously launched via its primary tile
                        * and relaunched via its primary tile.
                        * Cancel the navigation to resume. */
                    e.Cancel = true;
                    shouldClearJournal = false;
                }
            }
        }

        fastResumeExpired = false;
    }
}


The root frame’s Navigated event is raised after its Navigating event, unless the Cancel property of the NavigatingCancelEventArgs is set to true.

The RootFrame_Navigated handler, shown in Listing 3.3, keeps track of whether the previous navigation was a result of a Fast App Resume, which is indicated when the NavigationMode property of the NavigationEventArgs is equal to Reset. If so, and the timeout period has not expired, the page navigation stack is cleared using the RemoveBackEntry method of the root frame.

LISTING 3.3. App.RootFrame_Navigated Method


void RootFrame_Navigated(object sender, NavigationEventArgs e)
{
    NavigationMode mode = e.NavigationMode;

    if (previousNavigationWasReset && mode == NavigationMode.New)
    {
        if (shouldClearJournal)
        {
            Debug.WriteLine("Clearing history.");

            /* Clear the entire page stack. */
            var rootFrame = (PhoneApplicationFrame)RootVisual;
            while (rootFrame.RemoveBackEntry() != null)
            {
                /* Nothing to do. */
            }
        }
        else
        {
            shouldClearJournal = true;
        }
    }
    else
    {
        previousNavigationWasReset = mode == NavigationMode.Reset;
    }
}


The FastAppResumeView.xaml page located in the FastAppResume directory, in the WPUnleashed.Examples project, allows you to try out the different Fast App Resume scenarios. A button on the view is bound to an ICommand named CreateShellTileCommand that places a secondary tile on the Start Experience (see Listing 3.4). Resuming the app from the secondary tile causes the page navigation stack to be cleared.

LISTING 3.4. FastAppResumeViewModel Class


public class FastAppResumeViewModel : ViewModelBase
{
    string tileUrl = "/FastAppResume/DeepLinkedView.xaml?DeepLink=true";

    public FastAppResumeViewModel()
    {
        createShellTileCommand = new DelegateCommand(
            obj =>
            {
                if (!TileExists())
                {
                    CreateTile();
                }
            },
            obj => !TileExists());
    }

    bool TileExists()
    {
        ShellTile shellTile = ShellTile.ActiveTiles.FirstOrDefault(
            x => x.NavigationUri.ToString().Contains(tileUrl));

        return shellTile != null;
    }

    void CreateTile()
    {
        StandardTileData tileData = new StandardTileData
            {
                Title = "Unleashed Secondary",
            };

        /* Pin the tile to Start Experience.
            * This causes a navigation event and deactivation of the app. */
        ShellTile.Create(new Uri(tileUrl, UriKind.Relative), tileData);
    }

    readonly DelegateCommand createShellTileCommand;

    public ICommand CreateShellTileCommand
    {
        get
        {
            return createShellTileCommand;
        }
    }
}


Fast App Resume is an important new feature of the Windows Phone 8 OS that allows apps to forgo the usual startup penalty when being relaunched. Apps implementing this feature appear to start faster and give the impression of having better performance than apps that do not.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.2.78