This post is Day #14 in a series called the 31 Days of Windows Phone.
Yesterday, we talked about using Location data to give our applications a more custom, in-the-know kind of feel. Today, I’m writing on perhaps the most controversial topic available for Windows Phone 7: multitasking.
There’s been plenty of articles written about where Windows Phone 7 will struggle, and #1 at the top of that list is always “Lacks multi-tasking.”
Windows Phone 7 Does Multitasking
Yes. I said it. And I said it because it’s true. A Windows Phone is absolutely a multi-tasking device. I can listen to music while playing a game, or receive email while I’m surfing the web. Where the misinformation appears is when we, as developers of apps for the platform, discover that we can’t build apps that run in the background.
In the many months that I have been working with Windows Phone 7, I have only been able to come up with two really compelling reasons to need my application to run in the background on my phone.
- My app plays music. Like Pandora. I will completely concede that this needs to be able to be done in the background. The user will definitely notice if the music stops playing.
- My app needs data from the device’s sensors. Like GPS. If my app’s not running, I can’t tell you that you’ve run the 4 miles you wanted to run.
Outside of those two examples, however, I haven’t been presented with another situation in which having my app run in the background is necessary. (For those of you writing apps that DO fall into one of those categories, you can appeal to the “powers that be” for access to a “super API” that DOES allow background processing. I’ll warn you now though…you’re going to have to have a pretty compelling reason to get access to that.)
Before you say “but what about receiving updates from my web service? Don’t I need to be running to get those?” my answer is NO, no you don’t. There’s a great mechanism called Push Notification services that I will cover on Day #19 that solves this problem in a very elegant way.
For the rest of us, they’ve given us a great mechanism called “tombstoning” that allows us to pretend as if our application was always running, even though our process was killed. Here’s a quick diagram of how it works:
As you can see from the illustration above, there are deactivation and reactivation events that we can leverage when a user enters and exits our application. By using these events, we can make it appear to our user as if our application never stopped running. When we add in Isolated Storage (Day #15), and Push Notifications (Day #19), this becomes an incredibly powerful story.
Pretending to Multitask
There are four built-in methods in your App.xaml.cs file (for more information about the structure of your project files, check out Day #1). Here’s a quick look at their default state, with the default comments inline.
// Code to execute when the application is launching (eg, from Start) // This code will not execute when the application is reactivated private void Application_Launching(object sender, LaunchingEventArgs e) { } // Code to execute when the application is activated (brought to foreground) // This code will not execute when the application is first launched private void Application_Activated(object sender, ActivatedEventArgs e) { } // Code to execute when the application is deactivated (sent to background) // This code will not execute when the application is closing private void Application_Deactivated(object sender, DeactivatedEventArgs e) { } // Code to execute when the application is closing (eg, user hit Back) // This code will not execute when the application is deactivated private void Application_Closing(object sender, ClosingEventArgs e) { }
The “Launching” and “Closing” methods can be used in the traditional cases: starting and exiting the app through traditional methods (leaving with Back button, for example, or starting the app from the App List). The Activated and Deactivated methods are for those non-traditional entrances and exits. For example, using the Back button to go back to our application. Or leaving our app because the user answered a phone call. Those are non-traditional. I recommend testing these cases heavily, but those should be solid guidelines to start with.
You are supposed to use these methods to save your state when a user exits your application, and then refresh that state when they return, thus creating the illusion that they never left. The reason that we do this is pretty simple:
- Most users don’t realize that when they leave an application, it’s still eating system resources and battery life in the background. (If you’re reading this article, you’re NOT most users.)
- Most applications don’t NEED to run in the background. There are better ways to use the device’s resources.
Saving Your State on Deactivation
The first thing we’re going to want to do when the user exits is save their information. In my example application, we’re going to build a timer that appears to be running, even when it isn’t. If you want to see all of the code, flip down to the bottom of this article, and look for the “Download the Code” section. I’m only going to show the portions of the code relevant to tombstoning, but the entire application is available down there for you to play with.
To save data, I’m going to use the PhoneApplicationService. I’m going to cover Isolated Storage tomorrow (Day #15), a more persistent way to save your data. In my example, I want to know what time you exited my application, so that I can figure out the difference between when you exited and when you arrive the next time.
private void Application_Deactivated(object sender, DeactivatedEventArgs e) { PhoneApplicationService.Current.State["LeftTime"] = DateTime.Now; }
In my application, I also have an OnNavigatedTo event that fires when I load that page. If my “LeftTime” value exists, then I use that, otherwise, I assume you are starting the application for the first time.
Restoring Your State on Reactivation
In this example, I restore my values from the ones that I saved when I exited.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); if (PhoneApplicationService.Current.State.ContainsKey("LeftTime")) { DateTime deactivated = (DateTime)PhoneApplicationService.Current.State["LeftTime"]; secondsSinceStart = (int)(DateTime.Now - deactivated).TotalSeconds + (int)PhoneApplicationService.Current.State["ElapsedTime"]; writeTime(); writeDate(); timer.Start(); } else secondsSinceStart = 0; }
By using this method, I am able to keep a continuous timer, even when the user leaves my application. If you were to ask any user, they would tell you that the application is always running. The only indication they’ll get will be a quick glance at a “Resuming” screen that only shows up if your application loads slowly. I actually had to force my app to pause so that I could take the following screenshot:
So that’s the basic story behind tombstoning. Save your state on the way out, and restore it on the way back in. Your users will never know the difference, and you’ll give them better battery life, performance, and user experience.
Download the Code
A more complicated example of the code I showed above, my timer runs infinitely (even in the background). Press the Start button on the emulator to exit, and use the Back button to return. There’s also a TextBox you can enter text into, and it will save it when you exit.
Leave a Reply