Dealing with Tombstoning (XNA Game Studio 4.0 Programming)

On Windows Phone 7, the system controls the lifetime of your application.When your game isn’t in the foreground, the system can (and almost certainly will) stop the process.

What Is Tombstoning?

At the highest level, an application can have two states: It can either be running or it can be not running.Windows Phone 7 adds an extra state to the case where the application is not running. It can either be closed or it can be tombstoned. Tombstoning is when the process for the application is killed because it is no longer in the foreground, but the system remembers it because it might need to go back to that application.

For example, say your application is running, and the user clicks the home screen.Your application is no longer in the foreground, and the process is killed. It is tombstoned, but the system needs to remember it, because if the user clicks the Back button, your application needs to be shown again.

This concept is important enough that it bears repeating. If your application is not in the foreground, then it is not running.This can happen if the user clicks the home screen or if something as simple as your application launching one of the launchers or choosers available in Windows Phone 7 occurs.

Now, games and applications exit all the time, so this shouldn’t be a surprise to anyone; however, the difference is that the user’s perception should be that the game hasn’t exited. For example, while the user plays your game, she makes a phone call. She clicks the Windows button on the phone to get to the home screen, clicks the Phone button, and makes the call. Then she clicks the Back button to get back to the home screen, and then again to get back to the game.


From the user’s perspective, she should be in the same position now as she was before the phone call. She never quit the game; she simply navigated away and is now back. From the game’s perspective though, it was killed right after the user clicked the home screen and it was no longer in the foreground. This implies that your game needs to be smart enough to save its state before it’s killed, and reload that state when it starts up again after it is tombstoned.

Reacting to Tombstoning

For an easy way to detect a killed process, you can use a simple application. To do this, open the IsolatedStorage example you created in next topic,"Storage."Add the following variable to your game:

tmp2E-172

Use a simple frame counter to detect where you are in the game, so that you can restore it after the application is killed by tombstoning. To increment it every frame, add the following variable to your Update method:

tmp2E-173

 

 

To draw this counter, add the following to your Draw method before the spriteBatch.End call:

tmp2E-174

You don’t actually need two calls, but having the white text slightly offset from the black text gives it a nice contrast to the random small x that might be rendered everywhere. Every time you run the game, the frame counter starts at zero and begins incrementing, rather than starting where you left off if it was tombstoned.

Those who are familiar with the previous version of XNA Game Studio, and who want to easily make the game portable to other platforms that XNA supports, probably want to use the available events, and actually, in this example so far you already are. So, in your OnExiting override, add the following after you create the IsolatedStorageFile object:

tmp2E-175

This is similar to what you already did in that method. To read the frame counter back again, add the following to your OnActivating event after the creation of the IsolatedStorageFile object:

tmp2E-176

Run the game, let the frame counter increment some, and then click the Back button to exit the game. Restart the game and notice that like before, your data is loaded up at startup and your counter continues where it left off.Wait a minute and when you click the Back button, notice that you exit the game.You don’t need to save your state because it is exiting.

Now, unlike a Silverlight application, by default an XNA application does not exit if you press the Back button while the game runs. It exits only when you call the Game.Exit method (aside from when it tombstones, of course).You might not notice this because the default template for the new project includes this functionality. Notice it at the beginning of your Update method.You can use this knowledge to control when you save the data. Add a simple flag variable to know when you exit:

tmp2E-177

You can then modify your check for the Back button in the Update method to set the following value:

tmp2E-178

Now you know the difference in the OnExiting override between the system killing your process and the user actually quitting the game. So, update the code with the following to handle this situation:

tmp2E-179

The big difference is that if you actually exit the game, you delete the file that stores the current state.You can do something different—for example, you can leave the code as it was and replace the single write call with the following:

tmp2E-180

This works in this scenario, but is difficult in more complex situations. Sometimes, it’s easier to delete the file. Because the reading code is already handling the case of the file not existing, this works great. Now, if you run the game, let the frame counter get to a few hundred, click the Back button, and then run the game again, it restarts from zero. On the other hand, if you run the game, let the counter get to a few hundred, click the Home button, and then go back to the application, it restores the counter where it was!

Using Phone-Specific Features to Handle Tombstoning

Because XNA Game Studio is a cross platform API, it doesn’t always map exactly one to one to what the system is doing. For example, you get both the Deactivated and the Exiting event from the Game object if you either exit manually or are tombstoned.You also get the Activated event when you start up regardless of how you started.This makes it easy to write code that works on all platforms, but loses some of the nuances that a particular platform exposes.

Luckily, you can also use features specifically for the phone in order to do the same thing with more clarity about what is going on behind the scenes! First, add two new references to your project: one for Microsoft.Phone and the other for System.Windows. The APIs you need are in the first assembly, but they have a dependency on the second assembly and the system complains if you don’t add the second reference.You’ll also want to add another using statement to the top of your project:

tmp2E-181

Now, delete the code you added so far (or comment it out, because you will add similar code later).This time, you use the events the phone itself fires to determine which pieces of code to use.The phone fires four different events depending on the situation.

The Launching event occurs when the application launches for the first time, but does not occur when it comes back to life after it is tombstoned.The Activated event fires when the application comes back to life from being tombstoned, but not when it is launched the first time.The Deactivated event fires when you are about to be tomb-stoned, but not when you actually exit. Finally, the Closing event happens when the application actually exits, but not when it is tombstoned.

Armed with that knowledge, you can update your code to handle all of the scenarios required! First, because you want to save and load the point data in all scenarios, add the following two helper functions that you can use later.

tmp2E-182

 

 

 

tmp2E-183

This is the same functionality as before, but encapsulated in a method. So that you don’t need to create an IsolatedStorageFile object every time, add a new variable to your game:

tmp2E-184

To implement the tombstoning scenario using the phone events, add the following code to the end of your game constructor:

tmp2E-185

 

 

 

tmp2E-186

Now, you have fully handled all of the tombstoning scenarios.After creating the isolated storage file and handling the Launching event, all you need to do is load the point data.You don’t need to load your current frame counter because you won’t come back from being tombstoned! Next, you handle the Activated event, and here you again load the point data, but you also load the current frame counter because you’re coming back from being tombstoned.

Next, handle the Deactivated event, and save both the point data and the current frame counter because you’re being tombstoned. Finally, handle the Closing event, and because you are not being tombstoned, delete your current frame counter and save the point data.

Obviously, in a real game, the state you would need to save while being tombstoned would be more complicated, but you now should be able to save what you need at the appropriate times.You can never predict when your game will be tombstoned, so you need to handle it correctly.

Handling Graphics Resources During Tombstoning

The most difficult tombstoning task to grasp is how to reload content. As mentioned before, because the process is killed, everything needs to be reloaded.What’s worse, if your application doesn’t begin responding quick enough when activated after tombstoning, it could be completely killed or the user could be sent back to the home screen.

So, for example, if you keep all of the content loading in the LoadContent overload, but there is the content takes 10 or 15 seconds to load completely, your application may be completely killed, and the user is sent back to the home screen. This means you need to keep the reactivation code path fast, but also keep the user informed about what’s going on. The system displays a Resuming screen when it first starts reactivating the application, but after that, it is up to you.

If you have little content, you can load it all in the LoadContent menu. If you have content that might take a while to load, you only want a minor splash screen type of content to be loaded with the rest of your content loading after the activation has occurred. After the first Update and Draw methods have been called, your application is restored from tombstoning and you are free to load whatever content you like, although a good user experience shows the user progress if it takes a long time.

Summary

Tombstoning is one of the most important features to understand for Windows Phone 7 applications. It helps distinguish the great applications from the merely good (or even bad) ones.You need to do the work to ensure your applications handle it well.

Next post:

Previous post: