Why Deactivated is not the same as Tombstoned

With the transition from the Beta WP7 Dev tools to the RTM, an important and subtle change was introduced to the way launchers and choosers work.  In the beta, it was a given that every time we launched a launcher or chooser from Silverlight, the current application would be tombstoned and the Deactivated event would be thrown on the current PhoneApplicationService object.

With the RTM tools, this is no longer always the case.  Five tasks break this rule: CameraCaptureTask, EmailAddressChooserTask, MediaPlayerLauncher, PhoneNumberChooserTask and PhotoChooserTask.  In each case, while the application may be tombstoned, it also may not be.  In fact, most of the time, it will simply be paused and no tombstoning will occur – the application will not be terminated.  

We can assume that the typical workflow for a chooser task is the following (the images below demonstrate the PhoneChooserTask in action):

phonechooserback

A user performs an action that initiates a task.  The task window opens. The user either completes the task (in this case by selecting a contact) or presses the Back button to cancel the action.  The user is returned to the previous page.  In this case, it makes sense that no termination occurs.  Instead, the app is left in a Paused state much as an app is paused during incoming and outgoing calls – timers are suspended, no events are handled.

[Note: in the RTM, no event is fired when an application goes into a paused state.  At best, you can handle RootFrame.Obscured and RootFrame.Unobscured for incoming and outgoing calls.]

However, the user may also decide to press the Start button at the third step.   At that point it makes sense for termination to occur as it is less likely that the user will backpress back to the app.phonenumberchooser

So when should we handle the deactivated event for the second case where the user moves on and doesn’t complete a chooser task?  We actually can’t handle it when tombstoning occurs because our app is paused and will not respond to any events.

Instead, the PhoneNavigationService.Deactivated event is fired when chooser task (or MediaPlayerTask) is initiated.  This despite the fact that we don’t know (and can’t know) at this point whether the app will actually be tombstoned.

So far so good.  We may unnecessarily be writing objects to storage if the app isn’t ever tombstoned, but it’s better to be safe than sorry.

What is peculiar is that when we return to the app – either through the first scenario above or through the second deviant scenario – PhoneNavigationService.Activated is always thrown.  There’s a symmetry to this.  If the Deactivated event is called and we back into the application, then the Activated event will be called. 

The somewhat annoying thing is that the PhoneApplicationService should have enough information to avoid firing false Activated events unnecessarily.

No matter.  There is a simple trick for finding out whether an Activated event is real or fake – whether it truly follows a tombstoning of the application or is simply thrown because Deactivated was previously called.

Use a flag to find out if the App class was newed up.  It only gets newed up in two situations – when the application is first launched and when it is recovering from tombstoning.  Set the flag to false after the App class has finished loading.  If a chooser is launched and the application is paused but not tombstoned, the flag will still be false.  If tombstoning occurs, the flag will be reset to true.

private bool _isNewApp = true;

private void Application_Launching(object sender
    , LaunchingEventArgs e)
{
    _isNewApp = false;
}

private void Application_Activated(object sender
    , ActivatedEventArgs e)
{
    if (_isNewApp == true)
    {
        // a real tombstone event occurred
        // restore state
    }
    _isNewApp = false;
}

If you are handling tombstoning at the page level, you can similarly use a flag to determine whether the page was re-newed or not.

bool _isNewPage = true;

public MainPage()
{
    InitializeComponent();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (_isNewPage)
    {
        //restore state
    }
    _isNewPage = false;
}

The important thing to remember, though, is that the Deactivated / Activated events are not synonymous with tombstoning.  They simply occur alongside of tombstoning – and in the special cases described above occur when no tombstoning happens at all.

8 thoughts on “Why Deactivated is not the same as Tombstoned

  1. Terrific work! This is the type of information that are meant to be shared around the web. Disgrace on the seek for not positioning this post higher! Come on over and discuss with my web site . Thank you =)

  2. Simply want to say your article is as surprising. The clearness in your post is simply great and i can assume you are an expert on this subject. Fine with your permission let me to grab your RSS feed to keep up to date with forthcoming post. Thanks a million and please continue the rewarding work.

  3. Thanks for ones marvelous posting! I seriously enjoyed reading it, you're a great author.I will be sure to bookmark your blog and definitely will come back in the foreseeable future. I want to encourage you continue your great job, have a nice day!

Comments are closed.