Exiting a Windows Phone Application
[Update 12/31/2012: See also this post for a new Windows Phone 8 API to terminate apps]
[Update August 10th below]
A pretty common request both on the forums and on our internal discussion lists is "how do I exit my Silverlight application?" As you might imagine, this is something that we discussed at considerable length on the team before deciding not to expose such an API in Windows Phone 7.
The lay of the land
For the record, here are the various ways an application can be "exited" in Windows Phone; we'll discuss each in turn:
- An XNA application can call Game.Exit() to exit the game.
- The user can exit a Silverlight application by hitting the Back button on the first page of the application.
- The user can pause any application by hitting the Start button on any page of your application (or taking another action that switches to another application, such as tapping on a toast message).
- An unhandled exception in any application will cause the application to be killed
And an overview of the behaviour of each of them:
- #1 is only available to XNA applications. It will raise the Game.Exiting event
- #1 and #2 will raise the PhoneApplicationService.Closing event and your application (along with any saved State) will be removed from the back stack
- #3 will raise the PhoneApplicationService.Deactivated event and your application's pages (along with any saved State)will be preserved on the back stack until one of:
- The user re-launches your application via the Start Menu (or any other mechanism except the Back key)
- The application "falls off the end" of the back stack because it is full
- The device loses power, reboots, gets updated, the app is uninstalled, etc.
- #4 will kill your application and remove it from the back stack without raising any other events
Let's tackle the first one first. XNA applications have an explicit Exit method exposed for two main reasons: firstly the API already existed on Xbox and Windows so removing it could have caused a porting issue with other games, and secondly XNA doesn't participate in the page-based navigation model that Silverlight does and so there was no automatic way to handle the Back button. Nevertheless, section 5.2.4 of the application guidelines make it pretty clear when and how an XNA application should handle the Back key and when they should call Exit such that it is as consistent as possible with other applications. It may seem like XNA gets special treatment here, but really they are bound by the same rules that Silverlight is.
The second case is the way the user actually exits an application cleanly. After using the application, they will simply "back out" of it, closing any intermediate screens as necessary and finally closing the application when they back out of the first page. This is also a quick way to get out of an application if you launch it by accident (Start -> app appears -> Back) and is one reason why it's generally bad to automatically perform a navigation or show a popup when your application starts up (because now there will be two pages on the back stack). Give the user the option to log in (even if it's the only option on the screen!) but don't take up a slot in the back-stack for it on start-up.
The third case is also a common way to "quit" an application, except that it is kept on the back stack in case the user goes back to it (although some users may never really discover what the back stack does or how it works, but that's OK). If the user just wants to get on with some other activity and doesn't want to focus on your app right now they can just hit Start and go on their merry way (they could also hit Search, or tap on a toast, or do something else). If the user gets back to your application via the Back key, it will be restored with all the previous state (assuming you saved it correctly ;-) ) ready for them to continue their previous task. If, on the other hand, they start your application again from the Start menu then the old state will be thrown away and a new "session" of your application will start.
As an aside, a pretty common question we get asked is "How should I handle Deactivated vs. Closing, given that in both cases my application is shut down and the user may never come back to it?" The golden rule is that in both cases you should save any data that the user would not want to lose. Basically any data they've entrusted to the application that they would be unable (or unwilling) to enter again should be saved, even if it's only in a "draft" form. The key difference is that in the Closing case you don't need to worry about saving any view state or caching any information to enable a fast re-activation, whereas in the Deactivated case you should consider saving such information into the provided State bags (you should not persist this view state information to IsolatedStorage because it will be stale next time the application gets launched).
The final case is what happens if your application has a problem and you can't recover from it in the Application.UnhandledException event handler (in general it's a bad idea to unconditionally set e.Handled = true in this handler, because you have no idea what's going on... it's OK to handle specific errors that you know how to recover from though). The application will disappear from the screen and the user will be returned to the Start menu.
Scenarios for needing Exit
With the introduction out of the way, the two most common scenarios people cite when asking for an Exit method are because (a) the user failed accept a EULA, login to an account, or something else that renders the application inoperable, or (b) the application is in an unstable state due to unexpected errors, etc. and needs to be shut down.
We can quickly answer (b) by saying you should follow #4 above - simply ignore the error in your UnhandledException event and the application will be terminated for you. A simple way to do this can be to declare your own Exception subclass - say ApplicationNeedsToExitException - and explicitly check for that in your UnhandledException event handler. If you have an instance of that exception, immediately return from the handler without setting e.Handled to true, and you'll be set. There is the chance that some catch clauses may get the exception - in which case again you can explicitly catch this kind of exception and re-throw it - and / or that some finally clauses may execute as well. If that's the case you need to make sure they are "safe" to execute in the face of unexpected application state, but that's already the case for general exceptions.
That leaves (a), which I think is primarily caused by application designs carried over from other platforms like desktop Windows or other mobile platforms. Here's probably what happens:
- User starts the application
- It navigates to a EULA / Login / some other kind of "must successfully complete" page
- This may be the first page, or a popup, or even a forced navigation to a second page... which is bad as I note above
- The user declines the EULA / fails to login / etc.
- The application wants to programmatically exit
I think the reason that people want a programmatic way to exit is because they want to do something like this:
Of course, given this UI the user might expect that when they click "Decline" the application terminates (which is why the developer wants to call an Exit method) but there are at least two ways out of this. The most obvious one is to simply get rid of the "Decline" button! The user already knows they can quit an app using the Back key, so you don't need to give them another way to do that. No on-screen button = no need to call an API to exit. The other approach, if you really need an explicit "Decline" button, is to replace the page contents with a simple message like "You have declined the EULA and cannot use this application" and leave it to the user to hit Back themselves. Funnily enough, even if you had a programmatic way to exit the application, it would only be polite to afford the user the courtesy of such an explanation, in which case it would itself have an "OK" or "Dismiss" UX... and then you're back to just relying on the hardware Back button to accomplish the same task.
Lucky developers who already have a phone can see this if you try and add an e-mail account through the Settings control panel. The screen has an "Email address" field, a "Password" field, and a "Sign in" button. No need for a "Cancel" button, since you can always hit Back if you can't remember your login or want to abandon the account creation process. This is the interaction model of the phone, and we wanted to make sure everyone followed the same pattern to avoid confusing users.
[Update August 10]
I forgot the #1 piece of advice regarding EULA / Login screens - don't make them into pages. If you instead make them Popup controls you can show or hide them at any time (on first navigation; when the user hits a "protected" part of the app; after a time-out; etc.) and they don't consume a slot in the backstack. This should cover the majority of cases.
A third reason people sometimes cite for wanting an Exit method is because they want to have an explicit "Exit" menu item in their application so that the user doesn't have to hit Back, Back, Back, Back,... in order to get out of a deep page hierarchy and back to the Start menu. But that's what the Start button is for - if the user wants to get back to Start, they hit Start.
In this release of Windows Phone we've taken a fairly hard stance that applications should follow the user interaction model of 1st-party applications and should not have a programmatic way to exit themselves. Originally I was a proponent of having such a method primarily because I knew we'd get a lot of requests for it from developers (and would spend time explaining why it wasn't there... ha ha) but I am glad that I lost that argument for now because I think it will result in a more cohesive application ecosystem for users.
That said, it doesn't mean we can't or won't add such a method in the future if we get a lot of feedback that it really is necessary (for scenarios X, Y, and Z we didn't consider) or because we want to rationalize the API set with the other platforms or because it's Tuesday and we feel like it. For example, something like Environment.FailFast might be useful for apps that really do just want to log an error and bail. Or maybe it's too hard to write Silverlight games that act like XNA games with their explicit Exit call. If you have such scenarios (or just want to vent ;-) ), please leave a comment below.