Note: The following article was first published as part of the Windows Phone Recipe “Ways to Load Applications Faster” found here, which I wrote for Microsoft, together with Yochay Kiriaty.
Purpose of this Document
This document introduces the loading procedure for Windows Phone Silverlight applications. It explains common mistakes that application developers make during application launch, and how those errors can increase the total application load time and harm the user experience. Next, this document describes some possible solutions for overcoming long load times and explains their implementation.
Application startup is also discussed in Performance Considerations in Applications for Windows Phone. That paper provides excellent background information and can help make your Windows Phone applications shine.
Windows Phone Application Flow: Launching, Running, and Closing
We can't talk about proper loading techniques and optimizing application startup time without explaining Windows Phone application lifetime events. The following section provides a short overview; for more detailed information, see Execution Model for Windows Phone.
Windows Phone provides developers with a series of events and APIs for handling tombstoning and other application state changes, which include launching and closing. The PhoneApplicationService class, found in the Microsoft.Phone.Shell namespace, provides access to various aspects of the application’s lifetime, including management of the application’s state when it becomes active or inactive.
The PhoneApplicationService
class exposes four main lifetime events. For any auto- generated Windows Phone application (generated by Visual Studio 2010 Express for Windows Phone or Visual Studio 2010), the App.xaml.cs file includes four methods directly related to the execution model. These methods are your application handlers for the lifetime events exposed by the PhoneApplicationService
class:
Application_Launching
Application_Activated
Application_Deactivated
Application_Closing
The names of these methods are self-explanatory. However, there are some subtleties that we need to cover:
- Application Launching – A Windows Phone application is considered to be launched when it’s started by a means other than by the user pressing the Back button to return to a previous application. An application is launched when the user taps the entry for the application in the phone’s applications list or the tile for the application on Start. An application can also be launched when the user taps a toast notification.
- Application Deactivated occurs when a different application takes control of the foreground; for example, when the user launches a chooser or presses the Start button. In both cases, your application will be deactivated; the Deactivated event is raised, as opposed to the Closing event when your application exits. However, unlike an application that’s closed, a deactivated application will most likely get tombstoned. Don’t become confused: A tombstoned application’s underlying process still gets terminated, so your application does “close.” But unlike a closed application (which has exited), where the Windows Phone operating system removes any trace of the application from memory, in the deactivated scenario the Windows Phone operating system stores a record (a tombstone) of the application's state. Basically, the Windows Phone operating system keeps a tombstone of the application that becomes part of the phone’s application back-stack, which is a journal that enables the use of the Back button to enhance navigation functionality.
- Application Activated – After an application has been deactivated, it’s possible that it will never be reactivated. However, it’s also possible that the user will return to the application by pressing the Back button enough times to reach the application. When the user returns to a deactivated application, it’s reactivated and the Activated event is raised. Windows Phone then navigates to the last page viewed by the user in order to give the user the feeling that the application is simply continuing. Note that unlike Launching, some data objects in an Activated application might still be initialized.
- Application Closing is simply the outcome of the user pressing the Back button enough times to navigate backwards through the pages of your application, and past the application’s first page. Currently, this is the only way for a user to exit your application. Once your application is closed, its process is terminated, the operating system removes any trace of that application from its memory, and there’s no way to return to the application other than by launching a new instance.
Note that Launching
and Activated
events are mutually exclusive, as are the Deactivated
and Closing
events.
These events play a critical role in your application’s loading and closing times. Loading time also applies during application tombstoning and, more importantly, for applications resuming from tombstone.
One last note before we continue. There’s a certain sequence of methods that gets called during launching and tombstoning. This method sequence is critical for optimizing load time operations.
For the most part, when your application is launching or returning from tombstone, the following methods are being executed in the following order:
- Application constructor –
App()
found in App.xaml.cs - Application launching –
Application_Launching
found in App.xaml.cs - Your application’s “first page” constructor
- Your application’s “first page”
OnNavigatedTo
method
Note: When returning from tombstone, the “first page” is the last page the application was showing, and not necessarily the actual first page of the application.
Note: When your application returns from a tombstone state, this entire sequence is executed. However, in cases where tombstoning is relaxed, and your application is deactivated but not tombstoned, the Application constructor and the Page constructor aren’t executed. For additional information about Application Lifetime events and tombstoning, see Execution Model for Windows Phone.
Application launch time is defined from the time Windows Phone loads your application into memory and starts executing the application constructor (the first method in the sequence) until the end of the execution of the OnNavigatedTo
method first page.
Startup and Shutdown Times
Windows Phone enforces a series of time limits on application startup and shutdown in order to preserve a consistent and responsive user experience across the phone’s built-in applications and 3rd-party applications. If your application exceeds the allowed time for startup or shutdown, it will be forcibly terminated and removed from the back-stack. This means your application doesn’t get tombstoned, it’s simply terminated, and the user can’t use the back button to reactivate it. The following table outlines launch shutdown, deactivated, and reactivated times:
Table 1-1. Application Startup / Shutdown times
Application Event | Limit |
Starting the application (application Launching event)
| 10 sec
|
Forward navigating away from the application (application Deactivated event)
| 10 sec
|
Returning to the application using the Back key (application Activated event)
| 10 sec
|
Exiting from the application (application Closing event)
| 10 sec
|
You can see that you have up to 10 seconds of real-world time (this doesn’t mean that you have 100% of the CPU for 10 seconds) to handle each application lifetime event. If for some reason your code takes longer than 10 seconds to execute, the Windows Phone system will terminate your application.
Note: Besides the operating system safeguards, part of the Marketplace ingestion process is to check the time it takes to launch and to return from tombstoning. The user experience guidelines are even stricter, and require less than 10 seconds to properly launch your application. According to Windows Phone 7 Application Certification Requirements, the application must render the first screen within five seconds after launch, even when there’s a splash image. Therefore, optimizing and understanding the load sequence are critical to your application’s success.
- Startup time – Includes launching or returning to a tombstoned application. It’s the time from when your application process starts executing until your application becomes active or visible. Your application becomes visible only after the execution of the
OnNavigatedTo
method ends of the page the application navigates to upon launch or returning from tombstoning. Until then, the application’s splash screen is displayed and the application isn’t considered active. - Shutdown time – Includes deactivating and exiting from the application, and mostly consists of the time from when the forward navigation was invoked until the
Deactivated
or Closing
methods execution ends.
Demonstrating the Problem
As explained in the previous section, the application must complete its loading and display its first page (or any page when returning from tombstoning) within 10 seconds or the OS will kill the process. Moreover, even if your application launches in five or eight seconds, you still need to optimize the user experience by loading the application and displaying something as soon as possible; otherwise, the impatient user might tap the Back or Windows button to navigate away from your application.
So let's see how easy it is to create a well-behaved application. In the following demo, we’ll create a Windows Phone Silverlight application that needs to execute some long operations while loading.
Note: Our example application describes a very simple scenario for a Silverlight application that displays some information on the first page. This information should be obtained from some web service or local storage. To illustrate the problem, we create a fake workload that intentionally takes about 10 seconds to complete.
To simulate a long operation, we’ll simply trigger a function that sleeps for a second and reiterate that 10 times. (See the MyService.Init
methods below.)
To experience this first hand, simply follow these steps:
Step 1: Create a Windows Phone Application
Step 2: Create long workloads
public class MyService
{
private const int NumberOfIterations = 10;
public static void Init()
{
for (int i = 0; i < NumberOfIterations; ++i)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
public static void Init(Dispatcher dispatcher)
{
for (int i = 0; i < NumberOfIterations; ++i)
{
if (dispatcher != null)
{
dispatcher.BeginInvoke(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(1));
});
}
}
}
}
Essentially, both methods perform the same operation: they sleep for about 10 seconds to mimic a long workload. The second Init
method accepts a Dispatcher as an input parameter that we use each in sleep period. This forces a sync with the main user interface (UI) page (since that’s the dispatcher we’re passing in), as it isn’t reasonable to write code that completely blocks the UI thread for 10 seconds. Eventually, calling the dispatcher allows Windows Phone to terminate faster, as you’ll see later.
Step 3: Call the long workloads from various locations in your application
Call the function MyService.Init
from either one or all five methods:
public partial class App : Application
{
public App()
{
...
MyService.Init();
}
...
}
This event is raised when the user launches the application by tapping on the application’s icon.
public partial class App : Application
{
...
private void Application_Launching(object sender, LaunchingEventArgs e)
{
MyService.Init();
}
}
This event is raised when the user taps the Back key to return to the application, or after returning from a chooser or a launcher.
public partial class App : Application
{
...
private void Application_Activated(object sender, ActivatedEventArgs e)
{
MyService.Init();
}
}
This function is called when the Page
class is created.
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
MyService.Init(this.Dispatcher);
}
...
}
This function is called when the page is navigated to, either from another page or when the application gets launched/activated.
Note: The problem shown in this demo also can occur when your application comes back from a tombstone state, so you need to make sure you don't have lots of work in the constructor and OnNavigatedTo functions of any of your pages in the application.
public partial class MainPage : PhoneApplicationPage
{
...
protected override void OnNavigatedTo(NavigationEventArgs e)
{
MyService.Init(this.Dispatcher);
}
}
- App constructor
- Application
Launching
event - Application
Activated
event - Page constructor
- Page
OnNavigatedTo
method
Step 4: Run your Application
Simply run your application from your phone and observe that the operating system terminates your application. When it terminates, your application depends on specific implementation criteria, as explained below.
Note: To test whether the Windows Phone terminates your application when your application’s load time exceeds the 10-second limit, you must run your application on a real device without attaching the debugger. You need to deploy the application to the phone and then run it. Don’t run the application from Visual Studio, as when the debugger is attached (either to your Windows Phone device or to Windows Phone emulator); the relevant watchdog timers are disabled and the application will simply load after all the fake workload methods complete their task.
If you use the Init
without the dispatcher, then the sleep (on the main UI thread) prevents any operations from executing on the main thread (which is the main application thread). This is rather extreme and doesn’t represent a real-life scenario. So we’ve added a call to the dispatcher during each sleep period in order to sync back to the UI thread, and give the Silverlight runtime a chance to do what it’s supposed to do (terminate your application). Therefore, you’ll notice that when calling the MyService.Init
method without the parameter, the application will eventually get terminated, but only after all the sleep periods occur (depending on how many times you called the MyService.Init
method). When you pass the dispatcher as an input param (this is only possible in the MainPage
), you’ll notice that your application terminates faster.
Try removing the MyService.Init
method from the Application
constructor and Launching
method, but leave them in the MainPage
constructor and OnNavigatedTo
methods. You’ll see that it still takes about 11 or 12 seconds for the operating system to terminate your application. This again proves that it takes only one misbehaving method to significantly impair your application’s load time.
The Solution – Optimizing Your Application Load Time
Now that you understand the Windows Phone Silverlight application launch sequence and the problem of long launch times, it’s time to present some ways to optimize your application load times.
The solution is composed of four action items:
- Use a splash image
- Defer work
- Do work on a background Thread
- Use a loading page
Action Item 1: Use a Splash Image
The first thing you can do is to help to solve the user experience issue. If the user sees an image of the application that says "Loading…", he’ll wait a few more seconds before pressing the Back key out of frustration. Therefore, be smart and use a splash screen.
In fact, all Windows Phone project templates include a splash screen image. By default, this image is named SplashScreenImage.jpg, and it automatically appears when your application is starting. The default image looks like this:
Make sure to change the default image to something that suits the theme of your application. That way, when users see the splash screen (which happens instantly), they’ll recognize it as part of your application. Changing the default splash screen is also a Marketplace requirement.
Note: The image must have:
- A size of 480 by 800 pixels
- The filename set to SplashScreenImage.jpg
- The Build Action set to Content
Action Item 2: Defer Work
This is against everything your parents taught you, but when it comes to loading an application on Windows Phone, never do now what you can do later.
Postponing non-mission-critical work until after the application loads is always a good technique. At that point, you aren’t constrained by time issues, and you might have time to run workload between user actions.
For example, suppose you write a Sudoku game for Windows Phone. You might be tempted to generate the Sudoku game map when the application loads. However, it would be best to delay this action until the application is loaded and the user selects "New game." At this point, you can show some nice animation during the game setup process.
You should defer any workload that isn’t critical to the application launch and doesn’t have a severe impact on the user experience when the application loads. Always prefer lazy initialization of objects, which promotes deferring non-essential workloads.
Unfortunately, not every workload in your application launch sequence can be postponed. There are certain scenarios in which you can’t defer the workload to a later time in the application or until the user performs some operation. Some scenarios require you to run a workload as close as possible to the application start time. For example, consider an application that shows the top 10 trends currently on Twitter. Without the trends information, there’s nothing real to show on the application’s main page. However, we can't afford for the application to be terminated just because it’s getting the latest trends over the network.
To address scenarios in which your application has to complete some work close to startup time, you need to run some or all of the workloads in the background. This is exactly what we explain in the next section.
Action Item 3: Do Work on a Background Thread
This is probably the most important step in optimizing your application load time. To keep your application from hanging or terminating, the launch methods sequence must complete as soon as possible. If you can't defer a certain workload, you have to run that work in the background, that is, on a background thread.
You can use the following options:
using System.Threading;
Thread thread = new Thread(() => { MyService.Init(); });
thread.Start();
For additional information about manually creating threads, see the Thread Class documentation.
using System.Threading;
ThreadPool.QueueUserWorkItem((o) => { MyService.Init(); });
For additional information about using the thread pool, see the ThreadPool Class documentation.
By using the BackgroundWorker
class, you can assign a delegate that will perform the workload, as well as a callback method that will be executed once the delegate completes its operation.
To use the BackgroundWorker
class, you’ll need to add a using
statement for System.ComponentModel
.
using System.ComponentModel;
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork +=
(s,e) =>
{
MyService.Init();
};
backgroundWorker.RunWorkerCompleted +=
(s, e) =>
{
};
backgroundWorker.RunWorkerAsync();
- Manually create a thread
- Queue work item into the thread pool
- Use
BackgroundWorker
class
For additional information about using the BackgroundWorker
class, see the BackGroundWorker Class documentation.
When working with a background thread, you can’t directly update any UI control without marshaling to the UI thread from your back-thread. Silverlight offers a simple mechanism to do that by using the Dispatcher.BegineInvoke
method.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
});
Note: When working with background threads, you should always remember that UI components in Silverlight have thread affinity; that is, you can access a control only from the thread that created the control. So if you need to update the UI with progress/completed reports from the background thread, you should dispatch your code to run on the correct thread. This can be done by using the method myControl.Dispatcher.BeginInvoke(), where myControl is the control you want to update.
Action Item 4: Use a Loading Page
Now that you’ve moved some of the workload to the background, your application will load much faster and you should see your application’s first page rather quickly. However, most likely, you’ve got nothing meaningful (such as the new data you’re fetching) to show, since the background thread is still executing. Therefore, If you started some work on a background thread , you should consider showing a busy/loading indicator, like a progress bar, during the wait time.
You should avoid having a separate page for the loading indicator UI, since it would become part of the application’s page back stack. This would create a strange scenario in which pressing the Back button from the main page would return the user to the loading page rather than exiting the app.
Instead, in your main page, add a grid that contains two controls: the “loading control” that will show loading information (indicator), and the actual main page content. Toggle the Visibility
property of the two controls according to the current loading state. Also, if you set the ProgressBar
’s IsIndeterminate
property to true
, turn it off once you no longer need the loading screen, or you’ll have performance issues. You can read more about this at A ProgressBar With Text For Windows Phone 7.
For example, the following XAML shows how a main page could be structured:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid x:Name="loadingContent">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0,-30,0,0"
Text="Loading..."
/>
<ProgressBar
x:Name="progressBar"
Minimum="0"
Maximum="100"
/>
</Grid>
<Grid x:Name="mainPageContent" Visibility="Collapsed">
<TextBlock
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontSize="56"
Text="Main page data"
/>
</Grid>
</Grid>
The following code shows how to use the BackgroundWorker
class to do the work in the background, update the progress bar, and toggle Visibility
when the work’s done:
MyService.BackgroundWorker = new BackgroundWorker()
{
WorkerReportsProgress = true
};
MyService.BackgroundWorker.DoWork +=
(s, e) =>
{
MyService.Init();
};
MyService.BackgroundWorker.ProgressChanged +=
(s, e) =>
{
progressBar.Value = e.ProgressPercentage;
};
MyService.BackgroundWorker.RunWorkerCompleted +=
(s, e) =>
{
loadingContent.Visibility = Visibility.Collapsed;
mainPageContent.Visibility = Visibility.Visible;
};
MyService.BackgroundWorker.RunWorkerAsync();
In order to receive progress updates from the background thread, we passed the BackgroundWorker
to MyService
class, and use the ReportProgress
method:
public class MyService
{
private const int NumberOfIterations = 10;
public static BackgroundWorker BackgroundWorker { get; set; }
public static void Init()
{
for (int i = 0; i < NumberOfIterations; ++i)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
if (BackgroundWorker != null)
{
BackgroundWorker.ReportProgress((i+1) * 100 / NumberOfIterations);
}
}
}
...
}
Another way to toggle between the controls is to bind the Visibility
property of both the mainContent
and loadingContent
to a Boolean flag that signifies the loading state (for example, bool isLoading
). To do that, you’ll need a class that implements IValueConverter to convert from bool
to Visibility
.
Summary
Windows Phone applications must load fast and provide a good user experience. This is enforced by the application certification process and by the operating system. While the sample provided in this article is rather simple, the concepts remain true for all Windows Phone applications, and the techniques explained here will work for any Windows Phone application.
Another important consideration is the actual versus the perceived user experience. There’s more than one way to show loading progress, other than a progress bar, but it’s important to show something that’s meaningful and tells the user,“Hey, soon you’ll see your favorite app.”
That’s it for now,
Arik Poznanski.