WP7 Simplified: CoreApplicationService (Tombstoning)

This post brings closure to coverage of the CoreApplicationService (CAS) in this series titled WP7 Simplified. The final topic to cover is how the CAS handles tombstoning. Before getting into that let’s discuss what tombstoning is first. There are a couple of different terms to be familiar with that all refer to the tombstoning process: App Deactivation, Fast Application Switching, Tombstoning.

App Deactivation

When ever a user navigates leaving the app, except when they use the back button to close the app, the app is deactivated. All of the application state is stored in memory and app execution has 10 seconds to pause (Read the very last caution in the documentation). During deactivation it is important to store any transient and persistent state/data. From this state the application can be activated without losing any state in which case little if any state needs to be restored because the OS didn’t dispose of any part of the app state. The app could also be tombstoned which means that all state will need to be restored, but the application can still be activated. Finally the app might be completely closed by the OS thus requiring a fresh start.

Fast Application Switching

When an app is activating and the OS preserved state, the app should not attempt to do a full state restore, but instead should leverage the fact that the OS preserved the app’s previous state.

Tombstoning

If an app is tombstoned it means that all app state has been removed from the OS memory. This is why it is important for developers to store app state in transient or persistent data stores during app deactivation. When an app is activated from being tombstoned it should appear in the exact same state it was in before the user deactivated the app. It should also look the same as if the app had utilized Fast Application Switching.

For a much better explanation of these topics and some coverage of the difference between what persistent and transient data stores are available in Windows Phone please read my post Windows Phone 7 – Tombstoning.

Handling Tombstoning in CoreApplicationService

In the CAS only transient data is handled. We use DataProviders for persistent data. When deciding what transient data needs to be stored for tombstoning remember that we need to be able to restore the app during activation to the exact same state it was left in. Think of Leave No Trace from Boy Scouts and camping, we don’t want to leave any trace that the app was ever deactivated or tombstoned. Also, keep in mind when storing full objects that the object reference after retrieving a tombstoned value will be different than the object reference that was stored. If the reference needs to be the same the object should be stored in a persistent data store that should hand out the same reference for that object each time it is requested. We store values for tombstoning with the CAS using the following API.

public void StoreTombstoningValue(string key, object value)
{
	PhoneApplicationService.Current.State[key] = value;
}

public bool TryRetrieveTombstoningValue<T>(string key, out T value, bool clearKey = false)
{
	object tempObj;
	var exists = PhoneApplicationService.Current.State.TryGetValue(key, out tempObj) && tempObj is T;
	value = exists ? (T)tempObj : default(T);

	if (clearKey)
	{
		ClearTombstoningValue(key);
	}

	return exists;
}

public void RemoveTombstoningValue(string key)
{
	PhoneApplicationService.Current.State.Remove(key);
}

Store Tombstoning Value

Windows Phone provides developers with the PhoneApplication.Current.State dictionary which will survive as long as the app is not closed. Here is where we store all transient data.

Try Retrieve Tombstoning Value<T>

When retrieving a value we wanted to streamline the experience. Thus, this method is generic and does all the checks and casts each time a value is requested. It reports weather the value was found and cast correctly. It optionally takes in a parameter indicating to clear the value out of the State dictionary.

Remove Tombstoning Value

After retrieving a tombstoning value for the last time it should be removed to decrease memory usage.

Quick Tip of What to Store for Tombstoning

As much as possible only store object Id’s instead of the full objects. Even if at the moment the reference to that object doesn’t matter it may matter down the road. The naming of these methods is also very important. It is strongly suggested to not use the State dictionary to store objects during navigation. While it is true that a full object can be stored in the State dictionary before navigation for the next page to access after navigation, the object references are different because the State dictionary serializes and then deserializes all objects being stored then retrieved. This fact hurt one of our last projects. Once we had a grip on this principle we were OK, but until then bug after bug would manifest and they were difficult to track down.

Conclusion

Nothing super fancy this time. The motivation to include this functionality in the CAS was the constant repetition of the code in TryRetrieveTombstoningValue<T>(). It has helped clean up our code base quite a bit. This post also concludes code coverage of the CAS. The CAS is a very key component to any Windows Phone development. We’re excited to hear how you use it or how the principles discussed around it have helped you. Leave some comments to let us know. Next in the series we will be covering PageViewModel which works closely with ViewBase which we discussed in the previous post of this series WP7 Simplified: CoreApplicationService (Navigation).

Windows Phone 7 – Tombstoning

I looked all over the internet to find a good solid article on Tombstoning in Wp7, however it seemed like everyone had a different perspective and each came up a little short of what I wanted. The biggest problem is defining what Tombstoning really is. So lets begin with that.

Definition:

Tombstoning – Using the Deactivation event for the application in order to save state that will be restored during the Activation event.

It’s as simple as that. Now how can we save state? There are a few options to accomplish this.

Local Database (Persistent)

Working with Paul Rohde and Travis Schilling we created an application that utilized the local database for our application. It was pretty nice. It’s completely accessed by LINQ to SQL as far as we can tell. Travis was the man behind all of that work, and he seemed to say it wasn’t difficult once you understand how the DB is created.

IsolatedStorage (Persistent)

In Isolated Storage you have the option to save key-value paired rich objects in IsolatedStorageSettings.ApplicationSettings. This dictionary has a TryGetValue<T>(string name) method that is very useful. This makes for very quick saves of complex object graphs. There is also the option to save files using IsolatedStorageFile and IsolatedStorageFile. I have not used these, but they seem straight forward enough. Microsoft, however does not suggest using any IsolatedStorage options when trying to Tombstone. Why? It’s slower than the alternative PhoneApplicationService.Current.State dictionary.

PhoneApplicationService (Transient)

The PhoneApplicationService is the preferred way to Tombstone your application according to a post from Microsoft. It’s faster than any kind of persistent storage according to that post. You would use PhoneApplicationService.Current.State to add and read transient data. The downside to this dictionary is that the TryGetValue method is not generic by default. We’ll have to create an extension method to have it work the same as IsolatedStorageSettings’ TryGetValue<T>().

What data do I save?

This question, I think, used to be more cut and dry. I remember creating an application pre-Mango (7.5) and if you left the application then went back to the application no data would be persisted because the application was closed not Tombstoned. However I’m seeing that in Mango the current page being viewed when the application is deactivated is not reliably lost. A strange statement, however true. When I deactivate my application I’d expect the VisualTree and object graph to be lost, thus requiring me to save all of the required data during the Deactivated event so it could be restored during the Activation event. I’m not experiencing this. I’m seeing the object graph being kept around as well as associated VMs. Do I need to save this data since I can see it’s not being lost? After talking with Tim Askins we’ve decided it’s best to save the data even if we don’t need to restore it. The saying, “Better safe than sorry” comes to mind.

Best Practices and Cautions

  • Save all data that can be treated as Session data in PhoneApplicationService and store all permanent data in your preferred form of persistent storage (Database or IsolatedStorage).
  • Don’t try to call any web services that would normally be used to store the data if the application continued to run. If data needs to be sent to a web service, enable your application with a background task.
  • Remember you only have 10 SECONDS MAX to be fully Tombstoned before the OS will close your app.
  • Note that you should make sure all of your objects being stored in PhoneApplicationService or IsolatedStorage are marked as DataContract and each property is a DataMember. We also saw this was not really enforced, but I think it’s best practice to do this. Again, “Better safe than sorry.” Plus, Microsoft says that it is required.
  • Save persistent data as it’s changed rather than waiting for the application to be deactivated.

Launching/Closing vs. Activating/Deactivating

The Launching and Closing events should be used to load and save persistent data. Activating and Deactivating events should be used to load and save persistent and transient data. The less persistent data you must handle during Activation and Deactivation the better. Persistent storage is slower than transient storage and therefore reduces the user experience.

Special Thanks

After scoping out the web I’ve found the following links very helpful. Each have different perspectives and insights that I think are worth mentioning as part of the great whole called Tombstoning.