Thanks for visiting my blog!
In this fifth part of my Architecting Windows Phone 7 applications I will tackle the nature of tombstoning. If you’ve missed the past parts of the series, you you can visit them here:
- Part 1 (Navigation Framework)
- Part 2 (Pivot and Panorama)
- Part 3 (View Models)
- Part 4 (Client-side Data)
For the uninitiated, I think its important to understand the nature of how applications run on the Windows Phone 7. The nature of the phone is very different from Windows Mobile before it and Android is now. The way it works is to only allow one application to run at one time inside the sandbox. While some applications will have the ability to run in the background, they are specialized applications that do not run in ‘the sandbox’. Your applications will have to live without background processing. But how does this work?
For your application to be running, it has to be focused to the screen. In other words, if you can’t see your application, it isn’t running.
Switching away from your application can happen on a number of different cases including:
- User Presses Back from the first page of your application.
- User Presses the Home or Search button.
- User responds to a ‘toast’ notification.
- Interruption activity occurs (e.g. Phone call).
Closing your application via going back from the first screen causes your application to shut down. The rest of the ways your application stops running cause something informally called ‘tombstoning’ as shown below:
When your application is going to be tombstoned it enters a paused state where your application will be given an opportunity to temporary state. This saving of data is not to isolated storage but an in-memory store so that when your application is suspended it can be unloaded if necessary by the phone. If the user returns to your application (e.g. from the back key), your application is resumed which gives you the opportunity to take that temporary state and return your application to the same place it was when it was paused. The user should not notice this change. The whole idea here is to give you an opportunity to give the user a seamless transition from paused and resume without them knowing that the application was killed.
In my Moon Phaser application, I wanted to date picked by the user to remain the same during tombstoning. When the application is initially launched, the application always starts with the current date. As the user uses the application they can pick other dates. How does this actually work though?
In the App.xaml class file (App.xaml.cs or App.xaml.vb), there are four events for the lifecycle of the application. These events are actually wired up in the app.xaml file itself:
<Application ...>
<Application.ApplicationLifetimeObjects>
<shell:PhoneApplicationService
Launching="Application_Launching"
Closing="Application_Closing"
Activated="Application_Activated"
Deactivated="Application_Deactivated" />
</Application.ApplicationLifetimeObjects>
</Application>
The first two of these event handlers (Launching and Closing) are for the start and closing of your application. The next two are the critical tombstoning events (Activated and Deactivated). When your application is being deactivated, it is preparing to be suspended by the phone. You can save temporary state in this event handler:
void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
// The state bag to store your temporary state
IDictionary<string, object> state =
PhoneApplicationService.Current.State;
// Use the state to store your data
state["CurrentDate"] = ViewModel.CurrentDate;
}
In the event handler you can store the PhoneApplicationService’s Current property which includes a place to store the data (as a IDictionary object). You can store as many objects in this way as you want to. In this case I am using a member of the ViewModel (also a member of the Application class in this simple case).
When the application is brought back by the user though the Back button, the Activated event is fired:
void Application_Activated(object sender, ActivatedEventArgs e)
{
// The state bag for your temporary state
IDictionary<string, object> state =
PhoneApplicationService.Current.State;
// See if the bag contains the data
if (state.ContainsKey("CurrentDate"))
{
// Change the view model
ViewModel.CurrentDate = (DateTime)state["CurrentDate"];
}
}
As you should be using some central place for you date (e.g. a view-model or something similar), storing some of this state directly in the tombstoning state is the most common approach. Typically the data you store in the tombstoning state should be small and discrete. The expectation is that your application should return to its current state pretty quickly without having to reload a lot of state from tombstone state.
Another consideration is where to deal with state. You may decide to handle storing and getting state from within your pages instead of at the application. Because the PhoneApplicationService.Current is a singleton object, you can access it anywhere in your application. This means you can handle it at the page level instead like so:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
// ...
// Detect change in the date because of tombstoning
if (PhoneApplicationService.Current.StartupMode ==
StartupMode.Activate)
{
// The state bag for your temporary state
IDictionary<string, object> state =
PhoneApplicationService.Current.State;
// See if the bag contains the data
if (state.ContainsKey("CurrentDate"))
{
// Change the view model
_vm.CurrentDate = (DateTime)state["CurrentDate"];
}
}
}
Note that by using the PhoneApplicationService class, you can check whether an application was started from launching or activation (via the StartupMode enumeration).
You can decide to save your state at the page level too:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// The state bag to store your temporary state
IDictionary<string, object> state = PhoneApplicationService.Current.State;
// Use the state to store your data
state["CurrentDate"] = _vm.CurrentDate;
}
There isn’t a wrong or write answer on how to manage the tombstoning, but handling at the page level let’s you handle state as close to the consumption of data as possible instead of having to route everything from the Application class.
But you shouldn’t use tombstone state just because you can. For example, in my Stay Glucose to Me application, I don’t use tombstone state at all. Instead as my model changes, I save the entire model to isolated storage. This way as my application starts up or is activated, the code path is exactly the same.
Deciding how to handle tombstoning is one your challenges in architecting your Windows Phone 7 application.