Silverlight for Windows Phone 7: “Tombstoning”

July 14, 2010

This post will talk about tombstoning (what a name!) – the part of application lifecycle on Windows Phone 7.

The Windows Phone execution model governs the life cycle of applications running on a Windows Phone, from when the application is launched until it is terminated.

The execution model is designed to provide end users with a fast, responsive experience at all times. To achieve this, Windows Phone allows only one application to run at a time. This eliminates the possibility of users getting their device into a state where multiple applications are running in the background, causing the application in the foreground to become sluggish. image

In addition to responsiveness, the execution model provides users with a consistent navigation experience between applications. On Windows Phone, users navigate forward by launching applications from the installed applications list or from a tile on Start. Users can also navigate backwards, through the pages of a running application, or through the stack of previously running applications by using the hardware Back button.

To enable seamless navigation by limiting the phone to run one application at a time, Windows Phone activates and deactivates applications dynamically, exposing events to developers to respond to when the application state changes. By implementing handlers for these events, developers can save and restore application state as their application transitions between active and inactive states. This behavior creates an experience in which it seems to the user like the application continued to run in the background.

The procedure in which the operating system terminates an application’s process when the user navigates away from the application called Tombstoning. The operating system maintains state information about the application. If the user navigates back to the application, the operating system restarts the application process and passes the state data back to the application.

In addition the developer could use tombstoning events in order to preserve Application state and Page state.

Application state is a state of the application that is not associated with a specific page. Application state is managed in the events exposed by the PhoneApplicationService class.

Page state is a visual state of an application page. This includes such things as the scroll position of a ScrollViewer control and the contents of TextBox controls. Page state should be managed in the OnNavigatedTo and OnNavigatedFrom event handlers.

Most important – application is not guaranteed to wake up from tombstoned state, so preserve all really important things in persistent storage  (like Isolated Storage)! This will give you a chance to restore the data when application will be launched.

After short theoretical part lets get to business :)

Imagine you have multiple page application. Application collects some information from user and sends it to corporate server (WCF backend which will store the information somewhere) – in my case I have “Field Note” application, which allows to collect notes an send it to my WCF service. The service is very simple.

Data class:

[DataContract]
  public class Article
  {
    [DataMember]
    public Guid ID;

    [DataMember]
    public string Title;

    [DataMember]
    public string Body;

    [DataMember]
    public int AuthorID;

    [DataMember]
    public string AuthorName;

    [DataMember]
    public DateTime Date;
  }

The interface:

[ServiceContract(Namespace = "http://www.alexgolesh.com/services/StorageService")]
  public interface IStorageService
  {
    [OperationContract, WebGet]
    Guid SaveArticle(Article info);
  }

Phone application will submit data here… But before data could be submitted user first have to fill it out on the device. While writing simple “blah-blah-blah” on emulator is very fast task without real chance to be interrupted, composing real note could take some time and on real device many interruptions could happen, for example incoming call, user switches to calendar application to check exact dates related to the note, SMS arrived, etc. In all those cases application should preserve the state seamlessly to user (even giving the fact that the different application instance could be launched next time). From user’s point of view the unsaved/non-submitted data should stay. Here tombstoning events come to play.

Application template includes 2 events which will be launched when application being tombstoned (dehydrated) and when it comes back. In addition, 2 events will fire when application first launches and when it completely closes.

When the user taps the entry for the application in the phone’s installed applications list or the tile for the application on Start application starts, and Launching event is raised.

When application is running, there is a possibility is that the user presses the hardware Back button to navigate backwards through the pages of the application and even past the application’s first page. When this occurs, the Closing event is raised and the application is terminated.

When application is running and is subsequently replaced in the foreground by another application or experience, the first application will be deactivated. There are several ways in which this state can be invoked: an application will be deactivated if the user presses the Start button or  the device timeout causes the lock screen to be engaged or application invokes a Launcher or a Chooser. In any of these cases, the running application will be deactivated and the Deactivated event is raised.

When the application has been deactivated and tombstoned, it is possible that it will never be reactivated: user could launch the application again from Start invoking a new instance of the application, or the user could launch several other applications knocking the tombstoned application off of the back of the application stack where it cannot be reached with the Back button. It is also possible that the user will return to the application. This could happen if the user presses the Back hardware key until the application is reached or if a Launcher or Chooser was the cause of the deactivation, the user could complete the task or cancel out of it. When the user returns to a tombstoned application, it is reactivated and the Activated event is raised.

In my sample app I’ll preserve the unsaved date in Applicaton State in case of tombstoning, and will try to reload it in case of activation.

All the pages in my application are using the same data object, thus I initiated it as a DataContext for the Application’s Frame.

When deactivating:

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
  //Add current data object to Application state
  PhoneApplicationService.Current.State.Add(StateKey, RootFrame.DataContext as Article);
}

If it is lucky enough to get activated:

private void Application_Activated(object sender, ActivatedEventArgs e)
    {
      //Create new data object variable
      Article article = null;

      //Try to locate previous data in transient state of the application
      if (PhoneApplicationService.Current.State.ContainsKey(StateKey))
      {
        //If found, initialize the data variable and remove in from application's state
        article = PhoneApplicationService.Current.State[StateKey] as Article;
        PhoneApplicationService.Current.State.Remove(StateKey);
      }

      //If found set it as a DataContext for all the pages of the application
      //An application is not guaranteed to be activated after it has been tombstoned, 
      //thus if not found create new data object
      if (null != article)
        RootFrame.DataContext = article;
      else
        RootFrame.DataContext = new Article();

      (RootFrame.DataContext as Article).PropertyChanged += 
new System.ComponentModel.PropertyChangedEventHandler(article_PropertyChanged); }

Note: I’m subscribing to PropertyChanged of Article object in order to know when my data is “dirty” (changed).

When user closes the application, and for sure next time the new instance will ne activated I’m preserving the date in Isolated Storage:

private void Application_Closing(object sender, ClosingEventArgs e)
    {
      if (!(bool)Application.Current.Resources[IsSyncedKey])
      {
        using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
        {
          //If user choose to save, create a new file
          using (IsolatedStorageFileStream fs = isf.CreateFile(FileName))
          {
            //and serialize data
            XmlSerializer ser = new XmlSerializer(typeof(Article));
            ser.Serialize(fs, RootFrame.DataContext as Article);
          }
        }
      }
      else
      {
        using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
        {
          if (isf.FileExists(FileName))
            isf.DeleteFile(FileName); //delete synced data forom temp storage
        }
      }
    }

Note: I’m saving the date only if it still not synced with the server

When the user starts the application for the first time I need to check if I have some data from previous session, and if yes reload it for current session:

private void Application_Activated(object sender, ActivatedEventArgs e)
    {
      //Create new data object variable
      Article article = null;

      //Try to locate previous data in transient state of the application
      if (PhoneApplicationService.Current.State.ContainsKey(StateKey))
      {
        //If found, initialize the data variable and remove in from application's state
        article = PhoneApplicationService.Current.State[StateKey] as Article;
        PhoneApplicationService.Current.State.Remove(StateKey);
      }

      //If found set it as a DataContext for all the pages of the application
      //An application is not guaranteed to be activated after it has been tombstoned, 
      //thus if not found create new data object
      if (null != article)
        RootFrame.DataContext = article;
      else
        RootFrame.DataContext = new Article();

      (RootFrame.DataContext as Article).PropertyChanged += 
new System.ComponentModel.PropertyChangedEventHandler(article_PropertyChanged); }

Note: I’m subscribing to PropertyChanged of Article object in order to know when my data is “dirty” (changed) – exactly like I did in Activated case.

We almost there… My application UI (the page which really does data entry) looks like the following:

image

First two input fields are part of my Article object, but last one is not… this means it will not be preserved along with my data context… For such case I’ll use Page State and save this data in case of tombstoning there. In case of navigating away from the app itself I’ll save this info in Application Setting (in Isolated Storage). To hook up with page state I’ll override OnNavigatedTo and OnNavigatedFrom event handlers. They will fire in any case of arriving to the page and leaving the page.

First let’s look at OnNavigatedFrom:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
    {
      if (null == e.Content) //Navigating outside the application - application being tombstoned
      {
        //Save it also to Isolated storage, since application could not resurrect
        if (IsolatedStorageSettings.ApplicationSettings.Contains(stateKey))
          IsolatedStorageSettings.ApplicationSettings[stateKey] = txtPersonalNotes.Text;
        else
          IsolatedStorageSettings.ApplicationSettings.Add(stateKey, txtPersonalNotes.Text);

        //Anyway save it to page state
        if (State.ContainsKey(stateKey))
          State.Remove(stateKey);

        State.Add(stateKey, txtPersonalNotes.Text);
      }
      else //navigating back to first page - not tombstoned, state couldn't help here
      {
        if (PhoneApplicationService.Current.State.ContainsKey(stateKey))
          PhoneApplicationService.Current.State.Remove(stateKey);

        PhoneApplicationService.Current.State.Add(stateKey, txtPersonalNotes.Text);
      }

      base.OnNavigatedFrom(e);
    }

Note: if NavigationEventArgs has a Content, thus we are navigating inside the application. Alternatively you could check the Uri in NavigationEventArgs – if navigating away it will indicate “external”

image

When getting back to the page:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {

      //try to find the value in State first;
      //Will catch the resurrection and navigating from First Page
      if (State.ContainsKey(stateKey))
        txtPersonalNotes.Text = State[stateKey].ToString();
      else if (IsolatedStorageSettings.ApplicationSettings.Contains(stateKey)) //try to find in Isolated storage
      {
        txtPersonalNotes.Text = IsolatedStorageSettings.ApplicationSettings[stateKey].ToString();
        IsolatedStorageSettings.ApplicationSettings.Remove(stateKey);
      }
      else if (PhoneApplicationService.Current.State.ContainsKey(stateKey))
      {
        txtPersonalNotes.Text = PhoneApplicationService.Current.State[stateKey].ToString();

        PhoneApplicationService.Current.State.Remove(stateKey);
      }

      base.OnNavigatedTo(e);
    }

Well, thats it… The rest of logic not related to the tombstoning and could be skipped here.

Source for this sample is here.

Stay tuned for more,

Alex

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

3 comments

  1. David WhiteAugust 15, 2010 ב 3:25

    Your sample code has two cases for Application_Activated(). It would appear that in the second case you meant Application_Launching()?

    Reply
  2. Alex GoleshAugust 23, 2010 ב 10:05

    David:
    Yes, thanks :)

    Reply
  3. Anastasios-Antonios ToulkeridisDecember 18, 2010 ב 19:52

    hi from Greece,
    thanks for the excellent article

    Reply