Windows 8 Consumer Preview and Visual Studio 11 Beta – Process Lifetime Management (Part 11/11)

February 29, 2012

Windows 8 Metro applications introduces new (for desktop version of Windows) philosophy behind application execution – when application runs and when it is terminated. In this post I will overview this process also known as Process Lifetime Management (or PLM in short). In addition, I will showcase creation of custom Splash Screen experience which becomes important especially with in PLM in mind.


Windows 8 designed to run not only on desktop PCs and laptops (which usually have descent amount of RAM and CPU resources), but also on tablets and low-powered PCs (with limited amount or RAM, slower CPU and usually running from battery). New Windows 8 Metro applications are full-screen applications (most of the time), meaning that for given time only one (in some scenarios, like snapping – two) application interacts with user. With this in mind, it is simply not optimal to have more than one active application; applications which are not in foreground can be “suspended”. For us, developers, the experience is like pausing application on break point in Visual Studio’s debugger: the application is alive, all memory (and thus all variables and objects) preserved, but it is not executed. Such applications keep holding memory resources but will not run any process meaning will not waste CPU resource (which leads to lower battery drain).


The application lifecycle


So what really happens? When user launches the application (I will explain the “launch” term more in depth later) it begins invocation, shows Splash Screen (as defined in application manifest) and have only 15 seconds to present a window to the user.


Note: If application is not capable with this requirement it will be terminated (crashed). I will overview the ways to work around this behavior in Custom Splash Screen section.


When user launches additional application, first application being moved to background – it gets “suspended” signal and have 5 seconds to save its state. After saving state application remains in-memory, but not receiving CPU allocation and other system resources. If user returns to the application it resumes immediately, since it preserved in-memory and it is just a matter of continue running from previous time (remember Tombstoning and Fast Application Switch/FAS in Windows Phone 7?). Application gets “resuming” signal in order to restore its previous state.


Note: If application is not capable of finish saving state with 5 seconds from receiving “suspend” signal it will be terminated (crashed).


At some point of time there will be too much applications “suspended” in memory. In low-memory devices it will happen more frequently, on powerful desktop PCs probably less frequently but also happen. In this case new application launch will cause to system look for oldest and most memory-consuming suspended application and will remove it from memory or in other words terminate the app. Since application is not running it will not get any notification about the termination.


Note: Application must use “suspend” signal save its state and prepare for potential termination.


If user launches the terminated application again it will follow full application initialization process as it was during first launch.


In order to support this behavior, application provided by Suspending and Resuming events which can be registered and handled:

public App()
{
    this.InitializeComponent();
    this.Resuming += App_Resuming;
    this.Suspending += App_Suspending;
}
void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
    //Get deferral opreation
    SuspendingDeferral deferral = e.SuspendingOperation.GetDeferral();
    //Save state – 5 seconds only!

//…


    Windows.Storage.ApplicationData.Current.LocalSettings.Values.Add(“SUSPENDED”, DateTime.Now.ToString());

    System.Diagnostics.Debug.WriteLine(“Suspending the app“);
    //Notify complete with 5 seconds – otherwise the app will be crashed
    deferral.Complete();
}
void App_Resuming(object sender, object e)
{
    System.Diagnostics.Debug.WriteLine(“Resuming app“);
    //Reload state if resuming
    //…
    DateTime suspendedAt = DateTime.Parse(Windows.Storage.ApplicationData.Current.LocalSettings.Values["SUSPENDED"].ToString());     Windows.Storage.ApplicationData.Current.LocalSettings.Values.Remove(“SUSPENDED“);     System.Diagnostics.Debug.WriteLine(“Originally suspended at ” + suspendedAt.ToString());
}
SuspendingDeferral is class responsible to managing suspending operation. If application has nothing to save in its state (rarely occurred), it can just safely skip getting the deferral object or simply get it and immediately report Complete.

To debug Suspend/Resume/Terminate behavior VS11 provides Debug Location menu, which can be added to the menus bar:


image


image


How application lunched?


In Windows 8 application can be executed using multiple possible actions: user taps on application’s tile on main screen (or in all applications list), invokes search with the application, shares data with application, etc. Also when launching application from main screen tile, it can be first time launch or launch after application was suspended and terminated (as described above).  To deal with this, application provided with WinRT provides number of different overrideable functions at Application level – OnLauched and OnActivated (and all On_XXX_Activated).


OnLaunched event invokes when the application is launched normally by user and provides LaunchActivatedEventArgs which helps to deal with different possible launch conditions (launch kind, previous execution state, arguments, etc.).


LauchActivatedEventArgs.Kind helps manage different application launch scenarios depending on how it was launched:


image


LauchActivatedEventArgs.PreviousExecutionState helps to deal with situation when application was previously terminated/suspended to help create illusion of continues execution:


image


OnActivated (and other activated handlers like OnShareTargetActivated, OnFileActivated, OnSearchActivated, OnFileOpenPickerActivated and others) invoked when application activated either via file picker experience, share or search charm and provides relevant arguments for specific activation (like ShareOperation in case of share target activation, or search parameters in case of search activation) along with ActivationKing and PreviousExecutionState.


Custom Splash Screen


When application Activated or Launched it has only 15 seconds to present a windows. During this time system presents user with pre-defined Splash Screen. What if application needs potentially more time (for example getting data from cloud-based services)? What if application developer decides to provide some information about loading process? All those scenarios requires some custom splash screen (with potentially custom logic). But what happens with built-in one? How to deal with it?


For this scenarios OnLaunched and OnActivated events provide information about SplashScreen which used to get information about system-managed splash screen and provide seamless alternative with custom splash screen. In my sample I created custom splash screen, which “entertains” user for some time simulating real process behind the scene.


Let’s see the code. I created additional page, called ExtendedSplash which uses same image as declared in application manifest and have some additional elements to present text and waiting experience.


The page initialized as follows:

private SplashScreen splash;
private bool dismissed = false;
string activationArgs = null;
int count = 0;
string[] msgs = { “Loading…“,
Please wait…“,
Progressing really well…“,
Just few more blinks…“,
Finally! Done!” };
//Ctor
public ExtendedSplash(SplashScreen splashScreen, bool dismissed, string activationArgs)
{
    this.InitializeComponent();
    //Save system copy of splash screen for future reference and activation args
    splash = splashScreen;
    this.dismissed = dismissed;
    this.activationArgs = activationArgs;
    //move/resize local image exactly as on system splash screen
    extendedSplashImage.SetValue(Canvas.LeftProperty, splash.ImageLocation.X);
    extendedSplashImage.SetValue(Canvas.TopProperty, splash.ImageLocation.Y);
    extendedSplashImage.Height = splash.ImageLocation.Height;
    extendedSplashImage.Width = splash.ImageLocation.Width;
    //subscribe to resize event to handle new size of splash screen while active
    Window.Current.SizeChanged += new WindowSizeChangedEventHandler(ExtendedSplash_OnResize);
    //Simulate work by running timer…
    DispatcherTimer timer = new DispatcherTimer();
    timer.Interval = TimeSpan.FromSeconds(1);
    timer.Tick += (s, args) =>
    {
        count++;
        if (count < msgs.Length)
        {
            //Present next message to user to show some progress
            txtMessage.Text = msgs[count];
        }
        else if (count >= msgs.Length && this.dismissed)
        {
            timer.Stop();
            timer = null;            // When finished, navigate to real first page
            var rootFrame = new Frame();
            rootFrame.Navigate(typeof(BlankPage), activationArgs.Length == 0 ? null : activationArgs);
            // Place the frame in the current Window and ensure that it is active
            Window.Current.Content = rootFrame;
        }
    };
    timer.Start();
    txtMessage.Text = msgs[count];
}

When screen being resized:

void ExtendedSplash_OnResize(Object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
    // Safely update the splash screen image coordinates
    if (null != splash)
    {
        // Re-position the extended splash screen image due to window resize event.
        this.extendedSplashImage.SetValue(Canvas.LeftProperty, splash.ImageLocation.X);
        this.extendedSplashImage.SetValue(Canvas.TopProperty, splash.ImageLocation.Y);
        this.extendedSplashImage.Height = splash.ImageLocation.Height;
        this.extendedSplashImage.Width = splash.ImageLocation.Width;
    }
}

Finally, provide event handler function, which will be used in App class to subscribe for system splash screen dismiss event:

internal void dismissedEventHandler(Windows.ApplicationModel.Activation.SplashScreen sender, object e)
{
    this.dismissed = true;
}

In App class, redirect navigation to custom splash screen instead of real main screen:

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    SplashScreen splashScreen = args.SplashScreen;
    ExtendedSplash eSplash = new ExtendedSplash(splashScreen, false, args.Arguments);
    splashScreen.Dismissed += new TypedEventHandler<SplashScreen, object>(eSplash.dismissedEventHandler);
    Window.Current.Content = eSplash;
    Window.Current.Activate();
}

Running the app reveals seamless integration between system provided and custom splash screens:


image 


Note: In my case I decided to provided system splash screen for OnActivated experience, but same technique applies also on application activation


Working extended splash screen video:






Custom Splash Screen

That’s it for now.


Stay tuned for more interesting stuff to come!


Alex

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>