Condividi tramite


Part 2: Manage app life cycle and state (Windows Phone Store apps using JavaScript)

[ 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 ]

On Windows Phone, a user can launch and switch between multiple apps without decreasing performance or running down the battery. This is because Windows Phone automatically suspends, and sometimes terminates, apps that are running in the background. By saving your app state when it's suspended or terminated, and then restoring the state when the user relaunches your app, you can make it appear to the user that your app never stopped running.

Learn how to:

  • Save state using different types of roaming storage.
  • Restore your app's state the next time the app is launched.

Before you start...

This is the second tutorial in a 5-part series. Before you start this tutorial, see Part 1: Create a "Hello, world" app. This tutorial builds on the code you created in Part 1.

About the app life cycle

Part 1 of this series describes how the default.js file contains code that handles your app's activation. Before continuing, there are some important things to know about an app's life cycle.

An app is either running, suspended, or not running.

An app can be suspended when the user switches away from it or when the device enters a low-power state. While your app is suspended, it continues to reside in memory so a user can easily switch to the suspended app and resume it.

An app that is not running has no space in memory so there is no way to preserve its state. Apps can be terminated by the operating system to free up memory for other apps or to save power. Users can also manually terminate apps by pressing and holding the device's Back button and then pressing the Close button in the app. The app is suspended for approximately 1 to 10 seconds, and then it is removed from memory. The system notifies your app when it is suspended, but doesn't provide additional notification when your app is terminated. Your app must handle the suspended event and use it to save its state and release its exclusive resources and file handles immediately.

To create a good user experience, you want your app to look like it never stopped running. For example, your app needs to retain any data the user entered or settings they changed. To do this, you need to save your app's state when the app is suspended, in case the operating system terminates it, so you can restore its state later.

There are two types of data for you to manage in your app: app data and session data. App data persists across sessions and must always be accessible to the user. Session data is temporary information that is relevant to the user’s current session in your app.

In the following steps, you'll learn how to update your app to save these types of data. In the app you created in Part 1, so far the only thing the user can change is the name they've entered in the app and their toggle switch selection. The user also can click the Say "Hello" button to generate a personalized greeting.

Step 1: Save app data

Because app data persists across sessions, you can save information, such as user settings, so the user doesn't have to reconfigure the app every time they use it. In your app, the selection of the toggle switch is a great example of information to save with app data.

Because your app has only a short period of time to run code in the suspending event handler, you need to ensure that your important app data is saved to persistent storage by the time the app is suspended (or terminated). The best way to do this is to save app data incrementally when it changes, rather than all at once right before suspension.

You can use the Windows.Storage.ApplicationData object to help you manage app data. This object has a roamingSettings property that returns an ApplicationDataContainer. You can use this roaming ApplicationDataContainer to store user data that persists across sessions.

Note  This tutorial shows how to use roamingSettings. The roaming settings app data container makes it easy to store data so it's accessible to the user across multiple devices. Basically, the data is uploaded to the cloud in the background. You can also use the local settings app data container (localSettings), but you should use it when you want to store device-specific info.

 

Starting with the code from Part 1: Create a "Hello, world" app, store the user's toggle selection in the roaming ApplicationDataContainer.

To save app data

  • In your default.js file, add some code to save the ToggleSwitch selection in the ApplicationDataContainer for roaming settings.

    1. Call the Windows.Storage.ApplicationData.current property to get your app's ApplicationData object.
    2. Call the ApplicationData object's roamingSettings property to get your ApplicationDataContainer for roaming settings.
        function toggleChanged(eventInfo) {
            // Get the toggle control
            var toggleControl = document.getElementById("toggleControlDiv").winControl;
    
            // Get the greeting output
            var greetingOutput = document.getElementById("greetingOutput");
    
            // Set the CSS class for the greeting output based on the toggle's state
            if (toggleControl.checked == true) {
                greetingOutput.setAttribute("class", "toggle-on");
            }
            else {
                greetingOutput.removeAttribute("class", "toggle-on");
            }
    
            // Store the toggle selection for multiple sessions.
            var appData = Windows.Storage.ApplicationData.current;
            var roamingSettings = appData.roamingSettings;
            roamingSettings.values["toggleSelection"] = toggleControl.checked;
        }
    

That's all you need to do to save the selection of your ToggleSwitch. However, if you run, close, and relaunch your app now, you'll notice the selection doesn't appear to persist. That's because you need to add code to reload the state you just saved. However, first you need to save session data.

Step 2: Save session data

Session data is temporary data that is relevant to the user’s current session in your app. A session ends when the user terminates the app, restarts the device, or logs off (if they are using Windows 8.1). In your app, the text the user typed in the nameInput text box is session data. The user also may have pressed the button to display a personalized greeting. You only want to restore this information if the system suspends and terminates the app when the user didn't expect it to. To store session data, use the WinJS.Application.sessionState object.

Your default.js file contains an oncheckpoint event handler you can use to determine when to store session data. This event handler is called when your app is about to be suspended. However, it's best to save your session data incrementally, as it changes, like you did with your app data. In this case, save your session data whenever the user clicks the "Say "Hello"" button.

To save session data

  1. In your default.js file, create an event handler for the nameInputinput box's change event. Name the event handler nameInputChanged. Add this code just after the buttonClickHandler you created in Part 1.

        function nameInputChanged(eventInfo) {
    
        }
    
  2. Use the eventInfo object's srcElement property to access the nameInput control (the srcElement property retrieves the element that fired the event).

        function nameInputChanged(eventInfo) {
            var nameInput = eventInfo.srcElement;
    
        }
    
  3. Because the user's name entry needs to be saved only for the session, you store it in a WinJS.Application.sessionState object. To use the sessionState object, just add a property to it and set that property's value. Call the property nameInput.

        function nameInputChanged(eventInfo) {
            var nameInput = eventInfo.srcElement;
    
            // Save the session data. 
            WinJS.Application.sessionState.nameInput = nameInput.value; 
        }
    
  4. Save your personalized greeting output. Modify the buttonClickHandler to save the greeting output every time the user presses the button the same way you saved the name input, this time using a property called greetingOutput.

        function buttonClickHandler(eventInfo) {
            // Get the user's name input
            var userName = document.getElementById("nameInput").value;
    
            // Create the greeting string and set the greeting output to it
            var greetingString = "Hello, " + userName + "!";
            document.getElementById("greetingOutput").innerText = greetingString;
    
            // Save the session data. 
            WinJS.Application.sessionState.greetingOutput = greetingString;
        }
    

That's all you need to do to save your app's state before your app is terminated. Now you need to restore your app's state the next time the user launches the app.

Step 3: Restore app state

Take a close look at the code in the onactivated event handler that handles app activation. The first thing the code does is obtain a reference to your app and store it in a variable named app. Then it creates a variable named activation that refers to the Windows.ApplicationModel.Activation namespace. Both of these steps are completely optional. They simply reduce the amount of typing you have to do to refer to your app or to the Windows.ApplicationModel.Activation namespace.

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;

Next, the code defines an activated event handler. The handler checks to see what type of activation just happened. It does work only if the activation is a launch activation. When another type of activation happens, the handler doesn't do anything.

(You can expand the event handler to respond to other type of activations, but that's not covered in this tutorial. For more info, see Application life cycle.)

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
          

Next, the handler checks the previous execution state to see how the app was last shut down.

            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }

When the previous execution state is terminated, that means that the last time the app ran, the system successfully suspended the app and then terminated it. If the app wasn't terminated, the handler treats it as though it's being launched for the first time.

Finally, the handler calls WinJS.UI.processAll method and the code you added to register your event handlers. It calls this code every time the app launches, regardless of the previous execution state.

            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll().then(function completed() {

                // Retrieve the div that hosts the Toggle control.
                var toggleControlDiv = document.getElementById("toggleControlDiv");

                // Retrieve the actual Toggle control.
                var toggleControl = toggleControlDiv.winControl;

                // Register the event handler. 
                toggleControl.addEventListener("change", toggleChanged);

                // Retrieve the button and register our event handler. 
                var helloButton = document.getElementById("helloButton");
                helloButton.addEventListener("click", buttonClickHandler, false);

                // Retrieve the input element and register our
                // event handler.
                var nameInput = document.getElementById("nameInput");
                nameInput.addEventListener("change", nameInputChanged);

            }));

        }
    };

Now you can use the onactivated event handler to restore your app's state.

To restore app state

  1. When the previousExecutionState is terminated, load your personalized greeting and the name the user entered in the input box.

    In the else clause where the comments say to restore the app's state, check to see whether WinJS.Application.sessionState.greetingOutput has a value. If it does have a value, retrieve the greetingOutput div element and use it to display the greeting. Do the same for the name input.

        app.onactivated = function (args) {
            if (args.detail.kind === activation.ActivationKind.launch) {
                if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension.
                    // Restore application state here.
    
                    // Retrieve our greetingOutput session state info, 
                    // if it exists. 
                    var outputValue = WinJS.Application.sessionState.greetingOutput;
                    if (outputValue) {
                        var greetingOutput = document.getElementById("greetingOutput");
                        greetingOutput.innerText = outputValue;
                    }
                    // Retrieve our nameInput session state info, 
                    // if it exists. 
                    var inputValue = WinJS.Application.sessionState.nameInput;
                    if (inputValue) {
                        var nameInput = document.getElementById("nameInput");
                        nameInput.value = inputValue; 
                    }
                }
    
  2. Now load the state of the toggle switch. Because you want its state to persist across multiple sessions, you stored it in the roamingSettings app data container. Next, add some code to retrieve the app data container and set the state of the toggle switch, if it exists.

    You want this code to execute regardless of how the app shut down the last time it was run (you only need to check the previous execution state for session data), so you add it outside the if clause that checks the app's previous execution state. Now add it inside the then handler for WinJS.UI.processAll, where you register for your events.

        app.onactivated = function (args) {
            if (args.detail.kind === activation.ActivationKind.launch) {
                if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension.
                    // Restore application state here.
    
                    // Retrieve our greetingOutput session state info, 
                    // if it exists. 
                    var outputValue = WinJS.Application.sessionState.greetingOutput;
                    if (outputValue) {
                        var greetingOutput = document.getElementById("greetingOutput");
                        greetingOutput.innerText = outputValue;
                    }
                    var inputValue = WinJS.Application.sessionState.nameInput;
                    if (inputValue) {
                        var nameInput = document.getElementById("nameInput");
                        nameInput.value = inputValue; 
                    }
    
                }
                args.setPromise(WinJS.UI.processAll());
    
                // Retrieve the div that hosts the Toggle control.
                var toggleControlDiv = document.getElementById("toggleControlDiv");
    
                // Retrieve the actual Toggle control.
                var toggleControl = toggleControlDiv.winControl;
    
                // Register the event handler. 
                toggleControl.addEventListener("change", toggleChanged);
    
                // Retrieve the button and register our event handler. 
                var helloButton = document.getElementById("helloButton");
                helloButton.addEventListener("click", buttonClickHandler, false);
    
                // Retrieve the input element and register our
                // event handler.
                var nameInput = document.getElementById("nameInput");
                nameInput.addEventListener("change", nameInputChanged);
    
                // Restore app data. 
                var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
    
                // Restore the Toggle selection.
                var toggleSelection = roamingSettings.values["toggleSelection"];
                if (toggleSelection) {
                    toggleControl.checked = toggleSelection;
    
                    // Apply the properties of the toggle selection
                    var greetingOutput = document.getElementById("greetingOutput");
                    if (toggleControl.checked == true) {
                        greetingOutput.setAttribute("class", "toggle-on");
                    }
                    else {
                        greetingOutput.removeAttribute("class", "toggle-on");
                    }
                }
            }
        };
    

Now you can build and run the app and see how it saves and restores the session state. So far, you've tested your app by running it in debug mode and stopping it by selecting Stop Debugging in Microsoft Visual Studio. But doing this causes the app to perform a normal shutdown, and the Suspending event doesn't occur. Fortunately, in Visual Studio you can simulate suspending, terminating, and restoring an app.

To simulate suspending, terminating, and restoring an app in Visual Studio

  1. Press F5 to run the app in debug mode.

  2. Type your name in the input box and then click "Say "Hello"". Verify that the greeting is displayed.

  3. In Visual Studio, on the Debug Location toolbar, click Lifecycle Events, and then click Suspend and shutdown .

    The Debug toolbar is shown by default while the debugger is running. If you don't see it, on the View menu, click Toolbars, and then click Debug Location.

    Visual Studio simulates suspending and terminating your app in the Windows Phone 8.1 emulator, so the Suspending event occurs and your state management code is executed.

  4. Press F5 to run the app again. Verify that the app is restored to its previous state.

Summary

Congratulations, you've completed the tutorial! You learned how to manage your app's life cycle and save state. This tutorial showed you only two of the ways you can save app state. To learn more about the other ways you can save state, see Managing app data and Working with state efficiently.

Download the sample

Need more info, or you want to check your work? Download the Getting started with JavaScript sample.

Next steps

In the next tutorial in this series, you learn how to create a more complex app. Go to Part 3: PageControl objects and navigation.

Getting started with JavaScript: Complete code for the tutorial series