Handling suspend, resume, and activation in Hilo (Windows Store apps using JavaScript and HTML)

[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]

From: Developing an end-to-end Windows Store app using JavaScript: Hilo

Previous page | Next page

Hilo provides examples of how to suspend and activate a Windows Store app that uses JavaScript. You can use these examples to write an app that fully manages its execution life cycle. Suspension can happen at any time, and when it does you need to save your app's data so that the app can resume correctly.

Download

After you download the code, see Getting started with Hilo for instructions.

You will learn

  • How Windows determines an app's execution state.
  • How the app's activation history affects its behavior.
  • How to implement support for suspend, resume, and activation by using JavaScript.

Applies to

  • Windows Runtime for Windows 8
  • Windows Library for JavaScript
  • JavaScript

Tips for implementing suspend/resume

You should design your app to suspend correctly when the user moves away from it, or when there is a low power state. You should also design the app to resume correctly when the user moves back to it, or when Windows leaves the low power state. Here are some things to remember:

  • Save application data when the app is being suspended.
  • Resume your app in the state that the user left it in.
  • When navigating away from a page, save the page state to minimize the time required to suspend the app.
  • Allow views and presenters to save and restore state that's relevant to each. For example, if the user has typed text into a text box but hasn't yet tabbed out of the text box, you might want to save the partially entered text as view state. In Hilo, only presenters need to save state.
  • Release exclusive resources when the app is being suspended.
  • When the app resumes, update the UI if the content has changed.
  • When the app resumes after being terminated, use the saved application data to restore the app state.

For more info, see Guidelines for app suspend and resume (Windows Store apps).

[Top]

Understanding possible execution states

Which events occur when you activate an app depends on the app's execution history. There are five cases to consider. The cases correspond to the values of the Windows.ActivationModel.Activation.ApplicationExecutionState enumeration.

  • notRunning
  • terminated
  • closedByUser
  • suspended
  • running

Here's a diagram that shows how Windows determines an app's execution state. In the diagram, the blue rectangles indicate that the app isn't loaded into system memory. The gray rectangles indicate that the app is in memory. The blue arcs are changes that occur without any notification to the running app. The black arcs are actions that include app notification.

The execution state depends on the app's history. For example, when the user starts the app for the first time after installing it or after restarting Windows, the previous execution state is notRunning, and the state after activation is running. When activation occurs, the activation event arguments include a PreviousExecutionState property that indicates the state the app was in before it was activated.

If the user switches to a different app or if the system enters a low power mode of operation, Windows notifies the app that it's being suspended. At this time, you must save the navigation state and all user data that represents the user's session. You should also free exclusive system resources, like open files and network connections.

Windows allows 5 seconds for an app to handle the suspending event. If the suspending event handler doesn't complete within that amount of time, Windows behaves as though the app has stopped responding and terminates it.

After the app responds to the oncheckpoint (or suspending) event, its state is suspended. If the user switches back to the app, Windows resumes it and allows it to run again.

Windows might terminate an app (without notification) after it has been suspended. For example, if the device is low on resources it might reclaim resources that are held by suspended apps. If the user launches your app after Windows has terminated it, the app's previous execution state at the time of activation is terminated.

You can use the previous execution state to determine whether your app needs to restore the data that it saved when it was last suspended, or whether you must load your app's default data. In general, if the app stops responding or the user closes it, restarting the app should take the user to the app's default initial navigation state. When an app is activated after being terminated, it should load the application data that it saved during suspension so that the app appears as it did when it was suspended.

Note  When an app is suspended but hasn't yet been terminated, you can resume the app without restoring any state. The app will still be in memory. In this situation, you might need to reacquire resources and update the UI to reflect any changes to the environment that occurred while the app was suspended. For example, Hilo updates its app tile when resuming from the suspended state.

 

For a description of the suspend/resume process, see Application lifecycle (Windows Store apps). For more info about each of the possible previous execution states, see ApplicationExecutionState enumeration. You might also want to consult Guidelines for app suspend and resume (Windows Store apps) for info about the recommended user experience for suspend and resume.

[Top]

Code walkthrough of suspend

When Hilo starts, the bootstrapper registers a handler for the oncheckpoint (or suspending) event. Windows invokes this event handler before it suspends the app. Here's the code.

Hilo\default.js

app.addEventListener("checkpoint", function (args) {
    // The app is about to be suspended, so we save the current
    // navigation history.
    app.sessionState.history = nav.history;
}, false);

Hilo uses the event handler to synchronously save the app's navigation history to the sessionState object. The sessionState object is used for storing data that can be used to restore the app's state after it resumes from suspension. Any data stored in the sessionState object is automatically serialized to disk when the app is suspended.

Note  Because Windows allows 5 seconds for the app to handle the suspending event, any asynchronous events handled by the oncheckpoint handler must complete within this time frame.

 

When the app is suspended when the detail, rotate, or crop page is active, the QueryObject for that page is serialized so that when the app resumes, the correct photo can be loaded. Here’s the code.

Hilo\Hilo\imageQueryBuilder.js

toJSON: function () {
    return this;
},

The toJSON method is called automatically when the QueryObject is serialized. Though the implementation doesn't add anything beyond the in-built logic, it's included to demonstrate where the serialization could be customized if required.

[Top]

Code walkthrough of resume

When an app resumes from the suspended state, it enters the running state and continues from where it was when it was suspended. No application data is lost, because it was stored in memory.

It's possible that an app being resumed has been suspended for hours or even days. So, if the app has content or network connections that might need to be updated, these should be refreshed when the app resumes. When an app is suspended, it doesn't receive network or file event items that it registered to receive. In this situation, your app should test the network or file status when it resumes.

If an app registered an event handler for the resuming event, it is called when the app resumes from the suspended state. You can refresh your content by using this event handler. Hilo subscribes to the resuming event to refresh the thumbnails on the app's tile. Here's the code.

Hilo\default.js

Windows.UI.WebUI.WebUIApplication.addEventListener("resuming", function (args) {
    var tileUpdater = new Hilo.Tiles.TileUpdater();
    tileUpdater.update();
}, false);

[Top]

Code walkthrough of activation

When an app is started, the bootstrapper registers a handler for the onactivated event. A user can activate an app through a variety of contracts and extensions, but in Hilo we only needed to handle normal startup. So the onactivated event receives an object of type WebUILaunchActivatedEventArgs. This object contains an ApplicationExecutionState enumeration that indicates the app's previous execution state. Here's the code.

Hilo\default.js

app.addEventListener("activated", function (args) {

    var currentState = args.detail;

    if (currentState.kind === activation.ActivationKind.launch) {

        if (currentState.previousExecutionState !== activation.ApplicationExecutionState.terminated) {

            // When the app is started, we want to update its tile
            // on the start screen. Since this API is not accessible 
            // inside of Blend, we only invoke it when we are not in
            // design mode.
            if (!Windows.ApplicationModel.DesignMode.designModeEnabled) {
                var tileUpdater = new Hilo.Tiles.TileUpdater();
                tileUpdater.update();
            }

            // Begin listening for changes in the `picturesLibrary`.
            // If files are added, deleted, or modified, update the 
            // current screen accordingly.
            Hilo.contentChangedListener
                .listen(Windows.Storage.KnownFolders.picturesLibrary);

        } else {
            // This app has been reactivated from suspension.
            // Restore app state here.
        }

        // If any history is found in the `sessionState`, we need to
        // restore it.
        if (app.sessionState.history) {
            nav.history = app.sessionState.history;
        }

        // After we process the UI (search the DOM for data-win-control),
        // we'll navigate to the current page. These are async operations
        // and they will return a promise.
        var processAndNavigate = WinJS.UI
            .processAll()
            .then(function () {

                if (nav.location) {
                    nav.history.current.initialPlaceholder = true;
                    return nav.navigate(nav.location, nav.state);
                } else {
                    return nav.navigate(Hilo.navigator.home);
                }
            });

        args.setPromise(processAndNavigate);
    }
}, false);

The code checks whether the application is being started, and if it is, checks its previousExecutionState to determine whether the previous state was terminated. If the app wasn't terminated, the handler treats it as though it's being launched for the first time, so the tiles on the Start screen are updated. A handler is then registered for the contentschanged event, so that if the user's Pictures folder changes, the app is notified and responds accordingly. The handler is kept registered while the app is suspended, although the app doesn't receive contentschanged events while it's suspended. When the app resumes, it receives a single event that aggregates all the file system changes that occurred while the app was suspended.

Then, regardless of whether the previous state was terminated, any navigation history contained in the sessionState object is restored. The processAll function then processes the page and activates any WinJS controls that are declared in the page markup. Finally, if navigation history exists, the app navigates to the page that was displayed when the app was suspended. Otherwise, it navigates to the hub page.

If the previous state of the app was terminated, and when the app was suspended the detail, rotate, or crop page was active, the QueryObject for the page is deserialized so that the photo that was displayed when the app was suspended is reloaded.

Hilo\Hilo\imageQueryBuilder.js

deserialize: function (serializedQuery) {
    // Even though we pass in the entire query object, we really only care
    // about the settings. They allow us to reconstruct the correct query.
    var settings = serializedQuery.settings;

    if (typeof settings.monthAndYear === "string") {
        settings.monthAndYear = new Date(settings.monthAndYear);
    }

    return new QueryObject(settings);
}

The deserialize function takes a query object and uses the query object settings to reconstruct the query. The checkOptions function in pageControlHelper.js, which is invoked when each page is loaded, is responsible for calling the deserialize function. Here's the code.

Hilo\Hilo\controls\pageControlHelper.js

function checkOptions(options, deserialize) {
    if (!options) { return; }

    deserialize = deserialize || Hilo.ImageQueryBuilder.deserialize;

    if (options.query) {
        var original = options.query;
        var query = deserialize(original);

        // Copy any properties that were not produced 
        // from the deserialization.
        Object.keys(original).forEach(function (property) {
            if (!query[property]) {
                query[property] = original[property];
            }
        });

        options.query = query;
    }
}

The checkOptions function is invoked from page.js, with only the options parameter being passed. So, provided that the options variable contains data, the deserialize variable will be set to the deserialize function in the ImageQueryBuilder class. Then, provided that the options variable contains a JSON serialized query, and provided that the query isn't being executed, the deserialize function will be invoked to reconstruct the query object. Finally, any properties that weren't deserialized are copied to the query object.

[Top]

Other ways to close the app

Apps don't contain UI for closing the app, but users can choose to close an app by pressing Alt+F4, dragging the app to the bottom of the screen, or selecting the Close context menu for the app when it's in the sidebar. When an app is closed by any of these methods, it enters the notRunning state for approximately 10 seconds and then transitions to the closedByUser state.

Apps shouldn't close themselves programmatically as part of normal execution. When you close an app programmatically, Windows treats this as an app crash. The app enters the notRunning state and remains there until the user activates it again.

Here's a diagram that shows how Windows determines an app's execution state. Windows takes app crashes and user close actions into account, in addition to the suspend or resume state. In the diagram, the blue rectangles indicate that the app isn't loaded into system memory. The gray rectangles indicate that the app is in memory. The blue lines are changes that occur without any modification to the running app. The black lines are actions that include app notification.

[Top]