2. Tombstoning
The phone supports a concept called tombstoning.
The idea of tombstoning is essentially to give the illusion of
multitasking without the touch realities of running multiple
applications at the same time. To achieve this illusion, your
application can move between running, dormant, and suspended states, as
shown in Figure 5.
FIGURE 5 How tombstoning works
When your application is on the screen (visible
to the user), your application is in a running state. But a number of
things can interrupt your application, including a phone call, a “toast”
alert, or even the user pressing the Start or Search keys. When
something interrupts your application, your application is notified that
it is being deactivated. During deactivation you can
save certain data (or state) about your application. After deactivation
is complete, your process is moved to a dormant state.
In this state all the threads are suspended and no processing continues
to take place. If the operating system determines that it needs the
memory your dormant application is using, it will remove it from memory
(called the suspended state) but
will retain any data (state) you saved during deactivation. If the user
returns to your app (usually via the Back button), your application is
notified that it is being activated. During the
activation process, you will determine whether the phone was activated
from the dormant or suspended state, and either just restart the
application or use the saved state to return your application to its
original state. As far as the user is concerned, the application should
act just like it was running in the background.
This process is exposed to you via the PhoneApplicationService
class. An instance of this class is created in the App.xaml file of your project by default:
<Application ...>
<!--Application Resources-->
<Application.Resources>
</Application.Resources>
<Application.ApplicationLifetimeObjects>
<shell:PhoneApplicationService
Launching="Application_Launching"
Closing="Application_Closing"
Activated="Application_Activated"
Deactivated="Application_Deactivated" />
</Application.ApplicationLifetimeObjects>
</Application>
The PhoneApplicationService
class is created to have the same lifetime as the Application
class we discussed earlier. When it is created, it wires it up to four events in the Application
class itself. The default Windows Phone Application template creates
this object and wires it up for you. If you look at the App.xaml.cs/vb
file (where the Application
class is defined), you will see the corresponding methods that are mentioned in the App.xaml
class:
public partial class App : Application
{
// ...
private void Application_Launching(object sender,
LaunchingEventArgs e)
{
// ...
}
private void Application_Activated(object sender,
ActivatedEventArgs e)
{
// ...
}
private void Application_Deactivated(object sender,
DeactivatedEventArgs e)
{
// ...
}
private void Application_Closing(object sender,
ClosingEventArgs e)
{
// ...
}
// ...
}
These boilerplate functions are called as the state of your application changes. The first and last ones (Launching
and Closing
)
only happen when your application is first launched directly by the
user (for example, by clicking an application icon or responding to a
toast notification) and when the user closes the application (for
example, by pressing Back from the first page of the application). But
for tombstoning, the real magic happens in the other two handlers: Activated
and Deactivated
. These handlers are called during tombstoning to enable you to save and load state into your application.
To save your state, the PhoneApplicationService
class gives you access to a property bag to store data into. This class supports a State
property, which is an IDictionary<string, object>
collection that is used to store serializable objects by name. To use the class, simply use the class’s static Current
property to get at the current service object and use the State
property from there. Here is an example of storing a simple object (a color) into the State
property:
private void Application_Deactivated(object sender,
DeactivatedEventArgs e)
{
PhoneApplicationService.Current.State["favoriteColor"] = Colors.Red;
}
Note
If you are new to .NET, the concept of
serializable objects means whether an in-memory version of an object is
compatible with being written out in a format for temporary or permanent
storage. This storage is typically used to take objects in memory and
store them for rehydration back to memory objects. Serialization is used
when you’re storing objects in the PhoneApplicationService
’s State
collection, but it is also used when storing data to memory on the
phone, or even when you want to save data across a network connection.
The application is a common place to store this state, but because the PhoneApplicationService
class is where the real magic happens, you can handle that state
wherever you want. For example, in a single-page application, you might
use the PhoneApplicationService
class to store data as the page is navigated from (which happens during tombstoning as well):
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
PhoneApplicationService.Current
.State[MoodKey] = moodPicker.SelectedItem;
}
Because the PhoneApplicationService
’s Current
method always points to the current service for the application, you can use this state class anywhere.
When your application is activated, you can check the event
argument’s IsApplicationInstancePreserved
property to detect whether your application was dormant or actually
suspended. If it was suspended, you will need to recover the state saved
during the Deactivated
event:
private void Application_Activated(object sender,
ActivatedEventArgs e)
{
if (e.IsApplicationInstancePreserved)
{
// Nothing to do as your application was just 'Dormant'
}
else
{
// Recover State and resurrect your
// application from being 'Suspended'
var stateBag = PhoneApplicationService.Current.State;
var state = stateBag["favoriteColor"];
var color = (Color)state;
}
}
During activation you have a full 10 seconds to
process your data. Ten seconds ends up being a really long time and
should not be used as the benchmark. Users will
give up way before that. In general, tuning this to be as fast as
possible will give you a better user experience.
The Navigation Framework is part of an
application’s tombstone state by default, so when an application is
activated, the first page navigated to will be the last page the user
was on. In addition, the page stack is also preserved, so you do not
have to save this information manually. The applications will be
activated in the exact same place (navigation-wise) from which they were
deactivated. At this point, you should understand how the life of a
phone application works. Knowing that your application will need to deal
with a mix of navigation, tombstoning, and startup/shutdown behaviors
should equip you with the knowledge to build your application for the
phone.