(X) Hide this
    • Login
    • Join
      • Say No Bots Generate New Image
        By clicking 'Register' you accept the terms of use .

XNA for Silverlight developers: Part 11 - Tombstoning

(5 votes)
Peter Kuhn
>
Peter Kuhn
Joined Jan 05, 2011
Articles:   44
Comments:   29
More Articles
1 comments   /   posted on May 25, 2011
Categories:   Gaming , Windows Phone , General
Are you interested in creating games for Windows Phone 7 but don't have XNA experience?
Watch the recording of the recent intro webinar delivered by Peter Kuhn 'XNA for Windows Phone 7'.

This article is compatible with Windows Phone "Mango".
Latest update: Aug 1, 2011.

An often discussed topic on Windows Phone 7 is that of “tombstoning”, which describes the process of your application being suspended and removed from the running processes (think hibernate) to free resources on the phone. The application can be “revived” later when the user navigates back to it. It’s the developer’s responsibility to create a user experience that gives the appearance of a seamless transition between applications even when tombstoning happens. For games, the basic concept is the same as for other applications; however, the available possibilities seem slightly different. In this article, we learn about how to handle the application life cycle in conventional Silverlight applications, and how we can properly do the same in games developed with XNA.

Tombstoning in Silverlight

In a Silverlight application, what you do to handle tombstoning is use the PhoneApplicationService class. This class has a number of events that are raised at different times of the application lifecycle: Launching, Deactivated, Activated and Closing. The logic behind these events is pretty straight forward:

image

One of the interesting details is that your application might not get reactivated at all after deactivation (see the red arrow). If the user never navigates back to your application and instead e.g. launches a new instance using the start menu, or if your application is completely removed by the memory management at a later point, the Activated event will never occur. This is why you should make sure that all vital data is persisted in the Deactivated event handler, as your application may silently be fully terminated later, without being given another chance to store unsaved data.

Another important thing to know is that deactivation actually is not the same as tombstoning. When an application gets deactivated, it may also get tombstoned, but in certain situations it may not. The documentation mentions that e.g. if the user hits the start and back buttons in quick succession, tombstoning might not happen. It is also known that tombstoning either does not occur or is less likely to occur for certain choosers and launchers. And of course, if your application runs on a device that has the Windows Phone "Mango" update applied, not getting tombstoned right away even is the default behavior. Instead, on this updated platform your application is first put in a new state named "dormant", where it stays fully intact in memory (but without being granted any processing cycles). Only when the operating system needs to free memory for other tasks and applications later is your application eventually tombstoned. If the user returns to your dormant application before actual tombstoning happened, your application will be (almost) as if they never left, without the need to restore it manually for a persisted state.

Tombstoning in XNA

At first look, the Game class in XNA seems to have similar events for the application life cycle: Activated, Deactivated and Exiting. Since you create a game by inheriting from that class, it’s likely that instead of using the events you will override the corresponding methods instead: OnActivated, OnDeactivated and OnExiting. In the following paragraphs, I only talk about the events, but of course everything applies to the use of these overrides too. In addition, the game has an Initialize method that is called at the beginning and hence can be considered as a counterpart to the Launching event.

The problem with this is that the game class events work differently from the events of the PhoneApplicationService, making it much more difficult to handle tombstoning by using them. The sequence and combination the game class events are used also seems a bit confusing on Windows Phone at first. For example, the Activated and Deactivated events are not limited to situations of activation and deactivation; they’re also used when the game launches (Activated) and is shut down (Deactivated), in addition to the Initialize method and Exiting event. Even more confusing, the order these events happen in seems partly illogical. In my tests on both the emulator as well as on real devices, the Deactivated event happened after the Exiting event when the game was actually exited. For "normal" deactivation though the order of events was as expected.

Things become even more problematic with Windows Phone "Mango". When the user navigates away from the game, it is not tombstoned right away anymore, but put into the new dormant state I mentioned above. For the game class events this results in a different behavior with regards to the Deactivated and Exiting events. In RTM, both the Deactivated and Exiting events happen when the user navigates away (tombstoning situation), in Mango only the Deactivated event is used, but not the Exiting event (dormant state situation). Even if the application is tombstoned later, the Exiting event will never occur on Mango.

Initialize

Activated

Deactivated

Exiting

Game is started

x

x

 

 
Game is deactivated/tombstoned (RTM)

 

x

x

Game is deactivated/dormant (Mango)    

x

 
Game is reactivated

x

x

 

 
Game is exited

 

x

x

The reason for this seemingly messy behavior is that these events are not a specific feature of XNA on Windows Phone. In particular, these events were not made to handle the application life cycle on the phone. The original intention of these features on other platforms like the PC and XBox was to provide hooks for when the game gains and loses focus. Also, these other platforms don't have concepts like tombstoning or dormant states, which is why events like Exiting also cannot do justice to the Windows Phone platform down to every detail. The consequence of all this is that these events are not suitable to detect tombstoning or handle deactivation and activation reliably, as the behavior does not allow to distinguish between the different possible causes for the events.

Now, instead of trying to work around these limitations and somehow arrange with what we are offered by the game class, my recommendation is simple: make use of the PhoneApplicationService class in your games too, and do not rely on the respective events of the game class at all. This is a perfectly legitimate thing to do (it's actually even required for detecting the dormant state of Mango, see below), and we’ll look at that in more detail in a moment.

A note on the Guide class

As we’ve seen in previous articles, the Guide class can be used in XNA for simple dialogs, like message boxes and situations where the user has to provide user input. When you use this class and its dialogs, it’s important to know that they also trigger the Activated and Deactivated event of the game class, even though no tombstoning happens when the game is obscured by the dialogs. Once again the reason for this is that these events originally were meant to detect a focus loss, which of course indeed is what happens here. The corresponding events of the phone application service class are not raised in this case.

Some sample code

Let’s finally dive into a sample to see how all of the above translates into code. To be able to use the phone application service in your XNA game, you first need to add references to the following assemblies to your project:

Microsoft.Phone
System.Windows

From there, everything is pretty straight-forward. In your game's constructor, you can hook the events of the PhoneApplicationService class as you would in a conventional Silverlight application:

   1: // hook the events of the phone application service
   2: // to reliably detect launching, closing, and 
   3: // activation/deactivation/tombstoning
   4: PhoneApplicationService.Current.Launching += PhoneApplicationService_Launching;
   5: PhoneApplicationService.Current.Activated += PhoneApplicationService_Activated;
   6: PhoneApplicationService.Current.Deactivated += PhoneApplicationService_Deactivated;
   7: PhoneApplicationService.Current.Closing += PhoneApplicationService_Closing;

The actual event handlers then can be used to execute your logic. Just like for other applications, you would make sure that you store all vital data persistently (e.g. to isolated storage) in the Deactivated and Closing event handlers. Temporary data that is only relevant for the current session can be stored to the available transient storage places like the PhoneApplicationService's state property in the Deactivated event handler too. In the Activated event handler, you can restore your game state and also retrieve any temporary data from the transient storage. Finally, the Launching event handler is what replaces the Initialize method of the game and where you execute all the logic required to provide a "new instance launched" experience to your users.

   1: private void PhoneApplicationService_Launching(object sender, LaunchingEventArgs e)
   2: {
   3:     // here you would execute any logic required when the game launches
   4:     Debug.WriteLine("Launching.");
   5: }
   6:  
   7: private void PhoneApplicationService_Activated(object sender, ActivatedEventArgs e)
   8: {
   9:     // execute any logic required after activation
  10:     // => for example, restore from isolated storage, 
  11:     //    and retrieve temporary data from the transient state
  12:     Debug.WriteLine("Activated.");
  13: }
  14:  
  15: private void PhoneApplicationService_Deactivated(object sender, DeactivatedEventArgs e)
  16: {
  17:     // deactivation detected (may or may not result in tombstoning)
  18:     // => make sure all vital data is persisted, and all temporary 
  19:     //    data is stored to the transient state
  20:     Debug.WriteLine("Deactivated.");
  21: }
  22:  
  23: private void PhoneApplicationService_Closing(object sender, ClosingEventArgs e)
  24: {
  25:     // exit detected
  26:     // => make sure all vital data is persisted
  27:     Debug.WriteLine("Closing.");
  28: }

This is a very simple solution to the above mentioned problems that allows you to reliably handle the involved events of the application life cycle for your game too, without having to fight the limitations of the corresponding game class events. The much simpler and more consistent behavior of the PhoneApplicationService is shown by the following table:

Launching

Deactivated

Activated

Closing

Game is started

x

 

 
Game is deactivated/tombstoned (RTM)

x

 
Game is deactivated/dormant (Mango)  

x

 
Game is reactivated

x*

 
Game is closed      

x

 

Going dormant

In the above table, I marked the Activated event with a small asterisk to remind you that this is the once place where the involved code and logic is different for the RTM and Mango releases of Windows Phone. In particular, the event arguments for this event (ActivatedEventArgs) have been extended in the Mango release, where they contain a new boolean property named IsApplicationInstancePreserved. You should use this property to determine whether your game was actually tombstoned (false), or if it is simply activated after returning from the new dormant state (true).

In the latter case, you do not need to re-create the game's state and retrieve your data from e.g. isolated storage, like you usually would when the game is activated from tombstoning. All the state has been preserved, the game only was put into a frozen state in memory ("dormant"). So, the improved code for the Activated event handler in a Mango compatible game would look like this:

   1: private void PhoneApplicationService_Activated(object sender, ActivatedEventArgs e)
   2: {
   3:     // execute any logic required after activation
   4:     if (e.IsApplicationInstancePreserved)
   5:     {
   6:         // we are only returning from dormant state
   7:         // => no need to re-create any state, it has been preserved
   8:         Debug.WriteLine("Activated after dormant state.");
   9:     }
  10:     else
  11:     {
  12:         // we are returning from being tombstoned
  13:         // => restore from isolated storage, 
  14:         //    and retrieve temporary data from the transient state
  15:         Debug.WriteLine("Activated after being tombstoned.");
  16:     }
  17: }

With this small additional check, you have added support for the new fast application switching feature in Mango, and returning to your game when it hasn't actually been tombstoned will be much faster and smoother for your users – another great improvement of the user experience on Windows Phone which you get almost for free as a developer!

Testing dormant state and tombstoning

A quick note on how to test the new dormant state vs. real tombstoning. By default, when you have the Mango development tools installed, the emulator will behave like real devices and only put your application in the new dormant state upon deactivation during debugging. Sometimes however, you want to explicitly test the code and logic of your game that is executed when it was actually tombstoned. To simplify this, a new feature has been added on the property pages of your game project (tab "XNA Game Studio"):

image

This allows you to switch between testing tombstoning and the dormant state in the emulator. I talk a bit more about the new fast application switching feature in part 13 of this series.

Additional considerations and resources

This article doesn’t specifically talk about how to persist and restore data when deactivation and tombstoning happens. If you are interested in that, you can find quite some resources on the web about how to make your life easier with more generic approaches and mini-frameworks for this problem. I’ve written an article on the topic myself which in turn links to additional resources too. Also, even though this is a seemingly straight-forward topic, a lot of not so obvious problems can surface quickly. I’ve talked about the requirements and pitfalls in serializing data for tombstoning in detail in a separate article. This of course also all applies to games.

What we’ve learned here, and especially that last article I’ve just linked to, makes it obvious that tombstoning and properly saving and restoring your data is a topic you should plan ahead thoroughly. In fact, it is one of the crucial points that can make the difference for a great user experience. Even if your users don’t move away from your game deliberately, on the phone there are several unexpected situations that might lead to deactivation and/or tombstoning, for example incoming phone calls. Unfortunately, a lot of the games in the market place today force the player to e.g. restart a level from the beginning after tombstoning. In my eyes this is bad design; what you want to avoid in any case is punish your users for using their phone’s features. Of course it is ok to return to the menu or pause the game on reactivation, and offer an option to continue. But make sure that your game state is persisted and restored as accurately as possible, and users will love the experience.

Summary

I hope this article helped you learn about handling deactivation and tombstoning in XNA, and how to work around the limitations introduced by the built-in features of the Game base class by simply using the PhoneApplicationService in XNA too. We've also seen the new dormant state in Mango, and how easily you can support the new feature of fast application switching in your game.

The very small code samples you can download here only demonstrate the behavior of the built-in features of the Game class for both the RTM release and Mango, as well as the behavior of the PhoneApplicationState events that we’ve looked at in the second part of the article.

Download source code

About the author

Peter Kuhn aka "Mister Goodcat" has been working in the IT industry for more than ten years. After being a project lead and technical director for several years, developing database and device controlling applications in the field of medical software and bioinformatics as well as for knowledge management solutions, he founded his own business in 2010. Starting in 2001 he jumped onto the .NET wagon very early, and has also used Silverlight for business application development since version 2. Today he uses Silverlight, .NET and ASP.NET as his preferred development platforms and offers training and consulting around these technologies and general software design and development process questions.

He created his first game at the age of 11 on the Commodore 64 of his father and has finished several hobby and also commercial game projects since then. His last commercial project was the development of Painkiller:Resurrection, a game published in late 2009, which he supervised and contributed to as technical director in his free time. You can find his tech blog here: http://www.pitorque.de/MisterGoodcat/


Subscribe

Comments

  • harshitgoel96

    Re: XNA for Silverlight developers: Part 11 - Tombstoning


    posted by harshitgoel96 on Dec 10, 2012 17:42

    The reference needs to be specific to Microsoft.Phone.Shell.... 

Add Comment

Login to comment:
  *      *       

From this series