Application Life-cycle Management in Windows 8

  • 4/15/2013

Suspending

WinRT introduces a new concept in the application life cycle that consists of a two-phase process in which the application is suspended when the user leaves it to launch or activate a different one and resumed when the user switches back to it.

The idea behind this mechanism is to maintain the system responsiveness even if the user launches many applications. Only the foreground application uses processor time, while other applications are suspended by the system. There can be a maximum of two running apps when they are in snapped mode. Usually, when not in snapped mode, there will be only one foreground app. To avoid latency when the user comes back to a previously launched application, WinRT freezes the application memory when suspending an application and places it in a special idle state. No CPU cycle, disk, or network access is given to a suspended application. The result of this mechanism is that the system remains responsive while the resuming phase is practically instantaneous.

Verify the suspension of the application

In this procedure, you will test the suspension mechanism using the application you are building in this chapter.

  1. Launch the application from the Start screen. Avoid using the Visual Studio 2012 debugger to test the standard suspension behavior, because while debugging this behavior changes slightly.

  2. Close the dialog box that displays the launch message.

  3. Press Alt+Tab or the Windows key to put the current application in the background.

  4. Open Task Manager and wait until the application goes into the suspended status. To open Task Manager, you can press Windows+Q and search the term “Task Manager” in the Apps list, or you can activate the desktop from the Start screen and right-click the taskbar.

The result of this procedure is shown in Figure 4-10.

Figure 4-10

Figure 4-10 Using Task Manager to determine application state and resources.

As you can see, the ALMEvents application (PID 1220) is placed in the suspended state. It uses no processor time or disk access at all but, as stated earlier, it uses 7.9 MB of frozen memory. This value may be different on your system.

Switch back to the application by pressing Alt+Tab again and note that the application resumes instantly without showing a launch message dialog box because the application was just resumed from the suspended state.

WinRT will suspend the app as soon as it is in the background at least for 10 seconds. In case you put the app in the background for a time shorter than 10 seconds and you come back, the app probably will not be suspended.

In case of suspension, the system informs the application immediately before the suspension manager starts its work, and the application will have only five seconds to perform any suspension operations. If the app takes longer than five seconds to perform suspension operations, WinRT will terminate it forcibly.

It is very important to understand the complete flow of suspension/resuming before coding against it. The system suspends your app whenever the user switches to another app or to the desktop. The system resumes your app whenever the user switches back to it. When the system resumes your app, the content of your variables and data structures is the same as it was before the system suspended the app. The system restores the app exactly where it left off, so that it appears to the user as if it’s been running in the background. In practice, there is no need to save the data the user is working on during the suspension phase if the user comes back to the application. However, if the system does not have the resources to keep your app in memory, or it needs more resources for other applications launched by the user, the system will terminate your app. Your app will not be notified of the termination because WinRT assumes you have already saved any data or state information in the suspension phase. When the user switches back to a suspended app that has been terminated, the app receives a different launch, where you have to write the code that restores the application data.

Now that you understand the complete flow, you will add some code to the application you are developing in this chapter.

Use the Suspending event

In this procedure, you will modify the code for the App.xaml.cpp file to intercept the suspension and display a message dialog box. This is not what you would do in a real application, but it is important to understand the complete process.

  1. Open the App.xaml.cpp file.

  2. In the constructor, the Visual Studio Blank App template prepares the code to hook up the Suspending event as follows:

    App::App()
    {
            InitializeComponent();
            Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
    }
  3. Use the following code for the event handler for the Suspending event, replacing the existing code:

    void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
    {
            (void) sender;        // Unused parameter
            (void) e;        // Unused parameter
    
            Platform::String^ message = "App Suspending";
            auto dia = ref new Windows::UI::Popups::MessageDialog(message, "ALM Events");
            dia->ShowAsync();
    }
  4. Deploy the application and launch it from the Start screen.

  5. Close the dialog box that displays the launch.

  6. Press the Windows key to put the current application in the background.

  7. Open Task Manager and wait until the application is suspended.

  8. When the application is suspended, press Alt+Tab again to return to the application and verify that the message “App Suspending” appears.

This dialog box was shown during application suspension but, since the application was not in the foreground anymore, you saw nothing during the system operation. When you reactivate the application, WinRT resumes the application as it was prior to the suspension; this is why you can see the dialog box on the screen only during the resuming operation.

In practice, the dialog box is shown because the application has been resumed exactly where it was left off. The last thing the application did before the suspension was execute the call to display this message. You did not see this message during the suspension because the application was sent to the background.

Simulate an incorrect suspension

The application has only five seconds to respond to the suspension event. If the application needs more time, WinRT kills the application. In this procedure, you will try this behavior.

  1. Close the application if you left it open in the previous procedure.

  2. Open the App.xaml.cpp file, comment out the existing code of the OnSuspending method, and insert the bold line of code in the following excerpt:

    void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
    {
            (void) sender;        // Unused parameter
            (void) e;        // Unused parameter
    
            //Platform::String^ message = "App Suspending";
            //auto dia = ref new Windows::UI::Popups::MessageDialog(message, "ALM Events");
            //dia->ShowAsync();
            Concurrency::wait( 10000 );
    }

    This code simply waits 10 seconds—too much time for the system, which will kill the application after 5 seconds.

  3. Deploy the application.

  4. Open an instance of Task Manager and minimize it.

  5. Go to the Start screen by pressing the Windows key and launch the application.

  6. Maximize Task Manager.

    You can verify that after some time (maybe 20 seconds or more, depending on the system) the application disappears from the application list. This means that the application was killed by the system because the code for the suspending event exceeded the allowed time.

  7. Launch the application again and verify the message in the dialog box, which indicates the previous state as Terminated because the application was terminated (killed) by WinRT. This procedure can be slightly unpredictable since the runtime can decide to terminate the application later. This mechanism makes the debugging of the OnLaunched event very difficult and time consuming if you are trying to test for a previous termination, but don’t worry—at the end of this chapter, you will learn how you can simulate suspension, resuming, and termination from Visual Studio 2012 during a debugging phase.

Request more suspension time

If you need some more time—for instance, to persist some temporary data via web services or in the cloud—you can inform the system that you are executing an asynchronous operation. Call the SuspendingOperation.GetDeferral method to indicate that the app is saving its application data asynchronously. When the operation completes, the handler calls the SuspendingDeferral.Complete method to indicate that the app’s application data has been saved. If the app does not call the Complete method, the system assumes the app is not responding and terminates it. When the user launches the application, you should not rely on the validity of the saved application data.

The SuspendingOperation method has a deadline time. Make sure all your operations are completed by that time. You can ask the system for the deadline using the Deadline property of the SuspendingOperation method.

In this procedure, you will change the code for the event handler to write the suspension time on disk using an asynchronous deferred operation. Theoretically, this operation cannot last longer than five seconds, but this example shows the correct code to implement an asynchronous operation.

  1. Comment the line with the wait call.

  2. Add the code shown in bold in the following block:

    void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
    {
        (void) sender;        // Unused parameter
    
        //Platform::String^ message = "App Suspending";
        //auto dia = ref new Windows::UI::Popups::MessageDialog(message, "ALM Events");
        //dia->ShowAsync();
        //Concurrency::wait( 10000 );
        auto deferral = e->SuspendingOperation->GetDeferral();
    
        auto settingsValues = Windows::Storage::ApplicationData::Current->
            LocalSettings->Values;
        if (settingsValues->HasKey("SuspendedTime"))
        {
            settingsValues->Remove("SuspendedTime");
        }
    
        Windows::Globalization::Calendar^ now = ref new Windows::Globalization::Calendar();
        now->SetToNow();
        settingsValues->Insert("SuspendedTime", DateTimeFormatter::LongTime::get()->Format(
           now->GetDateTime()));
        // Perform the async operation
        deferral->Complete();

The first uncommented line gets the deferral from the SuspendingOperation property of the SuspendingEventArgs class. At the end, the code reports the completion of the deferred operation to the system.

The code gets the LocalSettings property of the application data and inserts a key called SuspendedTime with the current time in the collection. The LocalSettings class lets the developer save simple key/value pairs in the local application data folder. As you will learn in Chapter 10, “Architecting a Windows 8 app,” WinRT denies access to the classic file system and provides a local or roaming space, called application data, that applications can use to store data. This kind of storage recalls in many aspects the IsolatedStorage provided by the Silverlight and the Windows Phone runtime. You can also use a RoamingSettings property, instead of the LocalSettings one, if you want to share your app data across multiple devices. The RoamingSettings property is a cloud-based isolated storage, which relates the data to the current user’s Windows Live ID account.

You can also hook the suspending event inside the code of an application page. This is very useful to save the state of the page during the suspension to restore it in case of termination. Be aware that the Suspending event is not raised in the UI thread, so if you have to perform some UI operations, you need to use a dispatcher.

You can debug the code for the suspending method as usual, and you can also force a suspension during a debugging session from Visual Studio. You will try this functionality during the next procedure.