Mobile Corner

It's Universal: Understanding the Lifecycle of a Windows 10 Application

Nick Randolph pulls apart the lifecycle of a Windows 10 application and reveals what goes on programmatically when users launch, switch between and close Windows 10 apps.

Windows 10 represents the culmination of years of evolution toward a single application development platform that spans devices of all shapes and sizes, ranging from tiny Internet of Things (IoT) devices to the massive Microsoft Surface Hub.

Historically, Windows has been a multi-application environment where users can have multiple apps all running concurrently, with a simple action to switch between them. This model doesn't work well for phone- or tablet-style devices where the usage is typical single-application-focused.

As with other mobile platforms, Windows Phone permits only a single application to be in the foreground, with which the user interacts. This single-application focus doesn't work well when applied to a desktop environment, a point clearly shown by the disappointing, and often confusing, experience offered by Windows 8/8.1.

The Universal Windows Platform (UWP) for Windows 10 addresses these issues, offering a continuum whereby desktop users can still work with a multiple windowed experience, while in tablet mode and on the phone, usage reverts to a full-screen experience. In this article I'll take a closer look at how this experience is governed by the lifecycle of a UWP application.

At the most basic level, Windows applications exist in three states (see Figure 1): Not Running, Running and Suspended. Prior to being run, applications start in the Not Running state. After being launched/activated, applications transition to a Running state. Applications can be Suspended if they're no longer in the foreground. From the Suspended state applications can be resumed or terminated by the OS in order to reclaim system resources.

[Click on image for larger view.] Figure 1. Windows 10 Application Lifecycle

An application can be activated from a Not Running to Running state in a number of ways, such as being launched from the Start menu, tapping on a live tile, opening a file of an associated file type or even a custom protocol. In a number of these cases there are corresponding methods on the Application class that can be overridden in order to intercept when the application is activated.

For example, the default UWP project template overrides the OnLaunched method of the Application class in App.xaml.cs, which corresponds to the Launch activation type. In this method, a new Frame is instantiated and set as the Content of the current Window. The Frame is then navigated to the MainPage, before the Window is activated, which brings the Window to the foreground and gives it focus so that the user can interact with it.

The OnLaunched method can be a little confusing because it implies it will be invoked every time the application transitions from Not Running to Running. This is not the case, as it's possible to activate an application without the OnLaunched method being invoked. For example, if an application is assigned a custom protocol (see Figure 2), it can then be launched by opening a corresponding URL in Internet Explorer (for example, start:launchmyapp).

[Click on image for larger view.] Figure 2. Custom Protocol Assigned to a Windows App

Initially, launching the URL appears to do the right thing, as Internet Explorer will display a prompt confirming the launch of an application to handle the custom protocol. The application will launch but will not render the MainPage, displaying the splash screen, as in Figure 3.

[Click on image for larger view.] Figure 3. What You See with a Failed Activation

In this case, and for other types of activation, it's necessary to override alternative methods on the Application class. For example, for protocol activations, the OnActivated method should be overridden, or for file activations (that is, opening a file that has an extension that is associated with the application), the OnFileActivated method should be overridden. The argument to each of these activation methods implements the IActivatedEventArgs, which includes the ActivationKind, which can be used to determine how the application was activated, as well as the PreviousExecutionState, which, as the name suggests, indicates the previous state of the application. This can be used to determine if the application was terminated by the OS, or intentionally by the user, which in turn can be used to determine which page to display on start-up.

The transitions back and forth between Running and Suspended states raise corresponding events, Suspending and Resuming, on the Application, that can be intercepted. The event handlers for these methods are invoked synchronously. However, in some cases it is necessary to call asynchronous methods -- for example, saving data to disk is asynchronous. To do this it's possible to request a deferral that will prevent the application from suspending before the cleanup code completes, as shown here:

private void Suspending(object sender, SuspendingEventArgs e)
{
  var deferral = e.SuspendingOperation.GetDeferral();
  // Perform clean up operations
  deferral.Complete();
}

It's important to note that any synchronous code added to the event handlers for Suspending and Resuming should be kept to a minimum. Any substantial delays in the execution of these methods may result in the OS determining that the application is unresponsive and subsequently terminating the application.

When building applications for Windows Phone using Silverlight, when the user navigates away from the application to either another application or to the Start screen, a Deactivated event is raised that can be used to perform cleanup operations. This was relatively deterministic as the event was raised as soon as the application went out of focus.

In the UWP the Suspending event doesn't always get raised as soon as the application goes into the background. On Windows desktop, an application can lose focus, yet still be visible in the background. In this case the Suspending event isn't invoked immediately, and may only be invoked if the OS determines it's running low on system resources.

While debugging, UWP applications won't be suspended, even if they're minimized, or another application is switched to. In order to debug suspend and resume scenarios, use the Lifecycle Events dropdown (Figure 4) to force the application to Suspend or Resume.

[Click on image for larger view.] Figure 4. Lifecycle Events

After being suspended an application can be terminated by the OS in order to free up system resources. The transition back to Not Running doesn't raise any event or method override that a developer can intercept. For this reason, it's essential to include all cleanup actions in the event handler for the Suspending event. The next time the application is run, the PreviousExecutionState will indicate that the application was Terminated, which can be used to restore any state that would be relevant to what the user was last doing within the application.

The UWP introduces a number of new background tasks and ways to present a façade that an application is running in the background. One such extension uses an ExtendeExecutionSession to allow an application to continue executing for a period after the application is no longer in focus. Listing 1 starts in the OnSuspending event handler.

Listing 1: OnSuspending Event Handler
private async void OnSuspending(object sender, SuspendingEventArgs e) {
  var deferral = e.SuspendingOperation.GetDeferral();
  using (var session = new ExtendedExecutionSession())
  {
    session.Reason = ExtendedExecutionReason.SavingData;
    session.Description = "Saving Data to cloud";
    session.Revoked += ExtensionRevoked;

    var result = await session.RequestExtensionAsync();

    if (result ==ExtendedExecutionResult.Allowed)
    {
      await SavingDataToCloud();
    }
  }

  deferral.Complete();
}

private readonly ManualResetEvent waiter=new ManualResetEvent(false);
private async Task SavingDataToCloud()
{
  // Do some long-running task
  await Task.Run(() => waiter.WaitOne());
}

private void ExtensionRevoked(ExtendedExecutionSession sender, ExtendedExecutionRevokedEventArgs args)
{
  waiter.Set();
}

It acquires the deferral and then goes on to request extended execution. In this example the SavingDataToCloud method simply waits until the execution session is revoked. The ExtendedExecutionSession can be revoked at any point by the system. In the code, an event handler is attached to the Revoked event, and the result of the RequestExecutionAsync method is queried to determine if extended operation has been granted. While this code sample uses a ManualResetEvent, to cancel the SavingDataToCloud method when the execution session is revoked, the same could be achieved with a cancellation token.

Requesting an ExtendedExecutionSession requires both a Reason, which UX experience, if you know that the application will require an ExtendedExecutionSession, it's better to make the request as soon as possible -- this way, if the session is denied, an appropriate UX can be displayed, perhaps even allowing them to retry the failed operation. For example, if the user starts location tracking or turn-by-turn navigation, the application could immediately request an ExtendedExecutionSession to ensure it can continue to perform the necessarily location tracking in the background if the user switches away from the application.

Earlier I mentioned that the point where your application suspends and resumes isn't very deterministic. This makes it hard to refresh content when the application is suspended or resumed. An alternative is to connect an event handler to the Activated method of the current Window of the application:

Window.Current.Activated += WindowActivated;

private void WindowActivated(object sender, WindowActivatedEventArgs e)
{
  // Refresh page content and layout
}

The Activated event on the Window is particularly useful if you want to trigger and update, or refresh, operation whenever the user returns to the application. Remember that when your application is running on a Windows desktop, it may stay visible, even though it's not the application the user is currently interacting with. When the user switches to your application it may be necessary to update the application with any data that may have changed.

It's Universal
In this article I've set the scene for how applications for the Universal Windows Platform handle different methods and events in the application lifecycle. Considering how your applications will handle lifecycle events will help ensure your users don't lose data (for example, acquiring a deferral before long save operations to make sure the application doesn't close prematurely). Declaring support for -- and handling -- different activation methods, such as file types or custom protocols, will help drive engagement with your audience.

About the Author

Nick Randolph runs Built to Roam, a consulting company that specializes in training, mentoring and assisting other companies build mobile applications. With a heritage in rich client applications for both the desktop and a variety of mobile platforms, Nick currently presents, writes and educates on the Windows Phone platform.

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube