Mobile devices like phones, slates need operating systems that try and get the best out of the battery power that the device has while providing a fast, responsive experience for the user.
The operating system itself can do a tonne of work in this area but at some point the applications that are running on the device also need to do the right thing to make sure that the OS can do its job.
This surfaces itself in the “Application Lifecycles” that applications go through when running on a platform like Windows 8 or Windows Phone 8 and it’s one of the first things that would hit a traditional desktop developer coming from a Windows world as being very different from what they’re used to.
Generally, these lifecycles specify something like;
- The only app that runs is the one in front of the user.
- Other apps are put into some kind of suspended animation whereby their memory pages are preserved but they aren’t scheduled to run on CPUs.
- At some point the OS may actually kill a suspended app in order to reclaim the resources it was using.
- There’s the question of what to do if the user navigates back to an app that has been secretly suspended or even killed by the OS since they were using it.
and, usually, there’s some way of having other opportunities for code to run within the system ( “background tasks” ) such as on a particular interval or on a particular system event and the OS needs some mechanism for making the user aware of this and also ( via some kind of quota system ) of making sure that the “background tasks” don’t go crazy ( either by design or by error ) and start draining the user’s battery when they weren’t expecting it.
In recent times, I’ve been focused more on Windows 8 apps than Windows Phone apps so I wanted to try and write down where I thought I was up to with the Windows 8 model and then make some notes/comparisons with the Windows Phone model to get myself back up to speed there in the light of Windows Phone 8. That’s the rest of this post and, hopefully, it manages to avoid too many inaccuracies.
Windows 8
On Windows 8, the run->suspend->resume cycle feels relatively simple. If you’ve got an application like this one built in XAML and .NET (based on the blank template in Visual Studio) which is simply displaying a TextBox on the screen;
then what’s happened in that app is that the Application derived class (usually called App) has spun up, run the code in its OnLaunched override to create a Frame and navigate it to the MainPage page which displays the TextBox.
Window Visibility (are we on the screen?)
If I switch from this app to another app then I’ll get an immediate change in the visibility of my window such that this code;
Window.Current.VisibilityChanged += (s, e) => { if (e.Visible) { } };
would run to let me know whether my window was visible or not. If I was (e.g.) playing music in my app and I didn’t intend for that music to be background music then I might stop the music at the point where my window became invisible.
I think it’s important to flag that you can get these events because on Windows 8 if your app is moved from the foreground by the user it doesn’t immediately suspend but it will do in a few seconds…
Suspend/Resume
Even though my window might not be visible and the user might be looking at another app, my app is still running code at this point and will continue to do that for a while longer (about 8 seconds or so seems to be how it works out on the machines where I’ve watched it) then, unless I am running under the debugger, I will see my application suspend which means (to me) that the process is co-operatively brought to a safe stopping point and then it’s left around in memory but its threads aren’t scheduled by the OS. From a code point of view, I can handle this suspension event and its partner, the resume event;
DateTime suspendTime = DateTime.Now; Application.Current.Suspending += (s, x) => { suspendTime = DateTime.Now; Debug.WriteLine("Suspended"); }; Application.Current.Resuming += (s, x) => { TimeSpan suspensionTime = DateTime.Now - suspendTime; Debug.WriteLine( string.Format("Resumed after {0} seconds", suspensionTime.TotalSeconds)); };
and note that the Application derived class that the Visual Studio templates include already has a virtual method for you to override for OnSuspending.
If I navigate back to the app, it will resume. Note that if I was running under the debugger then this wouldn’t happen and I’d need to use the buttons on the toolbar to simulate suspend/resume;
and that if I wasn’t running under the debugger then a cheap and cheerful way of viewing my Debug.WriteLine messages is still with DebugView from www.sysinternals.com;
While the app is suspended, the user might well interact with it.
For instance, they might go back to the Start Screen and tap on its primary tile again. This would cause the application to be resumed and it would get its resume event and then carry on running.
Equally, if the application had a secondary tile on the start screen, the user might tap on that which would cause the application to be resumed but then also launched again for that secondary tile activation which might cause the app to navigate to a particular page dedicated to the arguments that were passed from the secondary tile.
Suspend/Terminate
An additional complication here is that while an application is suspended it might be terminated by the operating system if the OS decides that it’s getting a little low on resources as the user runs more applications.
If this happens, your primary “problem” as a developer is that the last interaction you had with the OS was at the point where you were suspended and you won’t hear from the OS again as it tears your process down.
However, this sort of thing is rightly hidden from the user so the general recommendation is that you try and preserve the user’s experience such that if this sort of sequence happens;
- User runs your app.
- User builds up some state in your app.
- User moves away to another app.
- OS suspends your app.
- OS terminates your app.
- User taps your tile again on the start screen to run your app again.
then your app would generally try and put the user back to where they were at step ( 2 ) unless you have good reasons for not doing so such as;
- perhaps the gap between step ( 3 ) and step ( 6 ) lasts for a long time which might make it hard for the user to remember why you have put them back in this state.
- perhaps at 6 the user taps a secondary tile on the start screen so doesn’t expect to go back to where they were in the application previously.
In order to make this work, the OS has to be able to tell an application when it launches whether it is in a “new” application launch or whether it is a launch of an application that was previously terminated and the OS does exactly that. In the override for OnLaunching in my Application derived class I can have;
protected override void OnLaunched(LaunchActivatedEventArgs args) { if (args.Kind == ActivationKind.Launch) { Debug.WriteLine( string.Format("Last time the app ran it was {0}", args.PreviousExecutionState.ToString())); }
and then if I run this up from “cold” inside the debugger I see output;
and then if I use the debugger to simulate suspend and terminate (which the debugger calls “Suspend and Shutdown”) which is the only way that I know of properly simulating this “OS” termination then the next time I run the app I see;
In terms of what you have to actually do as a programmer here to remember state information the basics of it are something like;
- Making a note of your user state as the app is going along (especially if it’s likely to get large). This state might also include things like the user’s navigation history around the app and the current page that they are viewing in the app if the app is a multi-page app.
- Handling the suspending event and writing out the saved state to disk.
- Optionally handling the resuming event and refreshing stale data if that’s relevant to your app.
- Handling the case where the application is launched from a previous termination and attempting to restore state on the user’s behalf to put them back where they were before the OS terminated their app by loading up the saved state and then getting rid of it.
In terms of doing this, if you use a Visual Studio template other than the blank template you’ll find in the XAML world that it comes with additional code in that there’s a class called SuspensionManager which adds;
- A global “session state” dictionary(string,object) of state for you to make use of.
- A means via which you can register a navigation Frame with the suspension manager and creates a separate dictionary(string,object) for each registered frame – most apps would have one.
- At suspension time the code serializes all of the state that it’s managing to a file within the app’s own folder structure including (1) and (2) above but also the navigation history of the Frame which the Frame itself can provide via GetNavigationState().
- At launch, the template code registers the Frame it creates with the SuspensionManager, checks the type of launch and attempts to restore all of the above in the scenario where the application was previously terminated and state has been saved and restored.
This works hand in hand with another class that the template code adds called LayoutAwarePage which;
- As it is navigated to, reserves itself a slot in the session state being held by its parent Frame to store a dictionary(string,object) for the state of that page.
- Offers an easy override for loading stored state from that dictionary as the page is navigated to.
- Offers an easy override for saving state into that dictionary as the page is navigated from (which will also happen prior to suspension).
- Works with the navigation frame such that these 2 scenarios can be coded in the same way;
- User goes to Main Page.
- User navigates to Page 1.
- User builds up some state (e.g. selecting some items in a list).
- Scenario 1
- User navigates to Page 2.
- User goes back to Page 1 and expects their state to be preserved.
- Scenario 2
- Application is suspended and terminated.
- User runs the application again and expects to land back on Page 1 with their state preserved.
- Scenario 1
The fundamentals of this suspend/resume/terminate/reincarnate cycle are the same whether you’re writing .NET code, JavaScript code or C++ code – the frameworks work differently on your behalf but the underlying concepts are the same whether you’re using your own code or whether you choose to lean on SuspensionManager and LayoutAwarePage from the templates or whether you’re in the WinJS world and make use of the WinJS.Application.sessionState object which does a similar job for you.
Closing Apps
This one is probably obvious but you can’t rely on the application ever being closed nicely by the user so if you have persistent state that the user modifies then you need to make sure it’s well and truly saved by the time suspension ends (or, ideally, before suspension even begins) because you don’t know if the app is going to run again or not.
Windows Phone 8
On Windows Phone 8, I find the lifecycle model ( which is detailed in the docs ) to be a bit more complicated and especially in the light of some of the changes that came with the new release like Fast Application Resume. Putting that new feature to one side for a moment…
A bit like Windows 8, on the Phone I run an app and then I can move away from that app either;
- Forwards by navigating to the Start Screen (or possibly into some OS chooser functionality like taking a photo but let’s leave that to one side).
- Backwards by navigating up the navigation stack and out of the application which causes it to exit.
And this is different from Windows 8 which does not maintain this navigation stack across applications – it’s not an operating system service on Windows 8 and although an application can offer the user a “back” navigation model across its own pages it’s not linked to the OS in any way so that a user can’t navigate “back” out of an application to close it down (instead, Windows 8 has specific ways of closing an application).
Deactivate/Activate and Dormant Apps
Additionally, the Phone model is different from Windows 8 in that as soon as I navigate forwards out of the application its code stops executing pretty much straight away. The app goes into a dormant state where it is still in memory but the code isn’t getting scheduled to run. For me, that dormant state is analogous to the Windows 8 suspended state but without the ~8 seconds it takes to make the transition.
If the user then goes back (i.e. uses the back button) to return to this dormant application then it’s a little like the Windows 8 suspend->resume cycle in that the app is still in memory, its threads start getting scheduled and it can run again and it might want to make a note of the time that elapsed between when the application went dormant and when it was activated and possibly refresh any stale data that it might be displaying.
In terms of code, the PhoneApplicationService makes events available to know when your app is deactivated and re-activated;
PhoneApplicationService.Current.Activated += (s, e) => { TimeSpan timeAway = (DateTime.Now - deactivationTime); Debug.WriteLine( string.Format("User came back after {0} seconds", timeAway.TotalSeconds)); }; PhoneApplicationService.Current.Deactivated += (s, e) => { deactivationTime = DateTime.Now; Debug.WriteLine( string.Format("User went forwards from the app at {0}", deactivationTime.ToLongTimeString())); };
and those are wired into your Application derived class in the Visual Studio templates. Also, those templates give you page classes derived from PhoneApplicationPage where you can override OnNavigatedTo and OnNavigatedFrom and so as the user leaves your page (for any reason) the OnNavigatedFrom method will get called and as they come back into your page the OnNavigatedTo method will get called.
Deactivate/Activate and Tombstoned Apps
On Windows 8, suspend is either followed by resume or by termination. On Windows Phone 8, going dormant may well be followed by another state transition into a tombstoned state.
If the application is tombstoned then it means that an instance of the application is kicking around on the navigation stack but the OS wants to reclaim resources being used by the application so the app goes away and the OS instead preserves some state dictionaries and navigation history information on the application’s behalf.
If the user then navigates back into the application it is brought back to life, the navigation history is restored and the page that was active at the time that the user left the application is put back onto the screen and the state dictionaries can be used to get everything back to where it was.
As an example, if I have an application with 2 pages;
where the buttons simply increment one of two counts (named Count1 and Count2!) and the display is databound to a single object defined in the App.xaml file which I treat as application data rather than page specific data and that object is an instance of this class;
public class AppData : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public AppData() { if (_current == null) { _current = this; } else { throw new InvalidOperationException("Can't make two of these, sorry"); } } public static AppData Current { get { return (_current); } } public int Count1 { get { return (this._count1); } set { if (this._count1 != value) { this._count1 = value; RaisePropertyChanged("Count1"); } } } public int Count2 { get { return (this._count2); } set { if (this._count2 != value) { this._count2 = value; RaisePropertyChanged("Count2"); } } } void RaisePropertyChanged(string property) { var handlers = this.PropertyChanged; if (handlers != null) { handlers(this, new PropertyChangedEventArgs(property)); } } int _count1; int _count2; static AppData _current; }
Then in the case where I perform a sequence of actions;
- Run the app.
- Increment the Count1 value to build up some state.
- Navigate to the second page in the app.
- Increment the Count2 value to build up a bit more state.
- Navigate forwards to the start screen and maybe another app.
- Navigate back to my app.
then most times this seems to work just fine and my backwards navigation lands me on the second page of the app with the right navigation history and the right values on the screen.
I say “most times” because if I involved tombstoning by using a debugger trick to force the app to tombstone each and every time I deactivate it by navigating forwards to another app;
then if I run through my app again;
- Visit main page, increment the state there
- Navigate to second page, increment the state there
- Navigate forward to another app via the start screen
- Navigate back
Then on that return navigation I’ll find that the system has preserved the navigation history for me in that my backwards navigation will land me on the second page of my app but I’ll find that it’s displaying the wrong data (0 values in my case). If I navigate back again then I’ll correctly land on the main page of my application but, again, the data displayed will be wrong.
This is because the app was tombstoned and I didn’t save and restore state so all the data that I had in memory has gone and this could happen to my app in real use so I need to cater for it.
If I added these 2 simple methods to my AppData class (taking a big dependency here on the PhoneApplicationService class);
public void Restore() { this.Count1 = (int)PhoneApplicationService.Current.State["count1"]; this.Count2 = (int)PhoneApplicationService.Current.State["count2"]; } public void Save() { PhoneApplicationService.Current.State["count1"] = this.Count1; PhoneApplicationService.Current.State["count2"] = this.Count2; }
and then if I wired those in so that they were called on Activation/Deactivation somewhere;
PhoneApplicationService.Current.Activated += (s, e) => { if (!e.IsApplicationInstancePreserved) { AppData.Current.Restore(); } }; PhoneApplicationService.Current.Deactivated += (s, e) => { AppData.Current.Save(); };
then my code would now survive the scenario of being tombstoned. Note that I’m not recommending that this is how you do things because the templates already wire in this state management into your Application derived class and your PhoneApplicationPage derived class – it’s just a simple example.
Terminated Apps and Relaunching
There’s another aspect to this Phone lifecycle that is different to Windows 8 because my Phone application can be terminated whether its tombstoned or dormant by following a process such as;
- Run my app.
- Increment my count on page 1 to build up some state.
- Navigate to page 2.
- Increment my count on page 2 to build up some state.
- Start screen.
- Run my app.
This is very different from the Windows 8 model. In the Windows 8 model, at step 6 the chances are that I would be working with the same application instance that I ran at step 1 (unless the app had been suspended/terminated in the meantime which is unlikely and, even then, the guidance is to preserve the user’s session with the app and make it look like nothing has changed).
On the Windows Phone 8 model, a new instance of my app is started at step 6 and the previous instance started at step 1 is discarded without any further notification to that instance. That instance is also removed from the navigation history so I can’t go back to it. It’s gone along with any navigation history from inside the app as well.
The guidance around this kind of scenario is that at step ( 6 ) a new app instance is what the user gets and any transient state from steps ( 2 ) to ( 4 ) is lost.
I must admit though that I find this aspect of usability on the phone confuses me as a user and even more so as a heavy user of Windows 8 because it’s so different from what happens on Windows 8 and that’s perhaps where this new “Fast Application Resume” feature comes in.
It’s also worth saying that the app instance from step 1 does not get a Closing event like it would if the user actually closed the app by navigating back from the app’s starting page. That means that an app cannot rely on getting its Closing event as a place to store any non transient data – it needs to do that either long before the app is deactivated or, at least, when deactivation occurs.
Fast Application Resume on Windows Phone 8
The way I understand “Fast Application Resume” is that it can make Windows Phone 8 apps behave more like Windows 8 apps with respect to this scenario where a user launches an app that is already “running” and taking up an entry on their navigation history.
If I switch on Fast Application Resume by editing the XML manifest;
Then if I go back to that previous sequence having turned off the feature in the debugger that forces tombstoning and I;
- Run my app.
- Increment my count on page 1 to build up some state.
- Navigate to page 2.
- Increment my count on page 2 to build up some state.
- Start screen.
- Run my app.
Then I find that at step 6 I’m back on the home page ( page 1 ) and the state that the app has built on the user’s behalf (in my case, 2 integer values) is preserved but I find that navigating back does not take me back to page 2 and then page 1 but, instead, it takes me out of the app and closes it down.
It’s as if the app has reset itself around page 1 rather than added a navigation to page 1 into its navigation stack.
Now, some of this is to do with the template that I used to create the app because it contains some code that does some work on my behalf. Specifically there is code in App.xaml.cs which hooks up to the Frame.Navigated event;
RootFrame.Navigated += CheckForResetNavigation;
and what that handler does is as below;
private void CheckForResetNavigation(object sender, NavigationEventArgs e) { // If the app has received a 'reset' navigation, then we need to check // on the next navigation to see if the page stack should be reset if (e.NavigationMode == NavigationMode.Reset) { RootFrame.Navigated += ClearBackStackAfterReset; } } private void ClearBackStackAfterReset(object sender, NavigationEventArgs e) { // Unregister the event so it doesn't get called again RootFrame.Navigated -= ClearBackStackAfterReset; // Only clear the stack for 'new' (forward) and 'refresh' navigations if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh) return; // For UI consistency, clear the entire page stack while (RootFrame.RemoveBackEntry() != null) { ; // do nothing } }
If I remove this code then when I “relaunch” my application using the previous listed steps the app still lands on page 1 whereas I’d expect it to land on page 2 because that was the page that I navigated away from back in step 5.
However, I notice that the navigation history is now as I’d like it to be because if I hit back I go back to “page 2” and then “page 1” again and then out of the application.
If I want to have step 6 land me back on the “page 2” that I last visited prior to deactivating the application then I can attempt to use the NavigationMode to try and spot when the application is being “fast resumed” and and cancel the navigation that this will involve (in my case because I re-launch from the primary tile that will be a navigation to the app’s main page (page 1)).
I’m not 100% sure that I’m doing this the right way as it seemed to contrast with the docs slightly but I addedcode to my App.xaml.cs in the InitialisePhoneApplication method;
bool cancelNextNavigation = false; RootFrame.Navigating += (s, e) => { // TODO: Not 100% sure this is right. if (e.NavigationMode == NavigationMode.Reset) { cancelNextNavigation = true; } if ((e.NavigationMode == NavigationMode.New) && e.IsCancelable && cancelNextNavigation) { e.Cancel = true; cancelNextNavigation = false; } };
and that seems to work for me in this specific case and that’s also true if I switch on the debugging flag that forces tombstoning again just to make sure that it’s consistent whether the app that’s being re-launched is dormant or tombstoned.
Debugging on Windows Phone 8
One tip I’ll share when debugging on Windows Phone 8 (I was debugging across to my Lumia 920) is that I find it a bit confusing/magical when I’m trying to reason about which instance of my application I’m actually debugging on the phone and when that is or is not changing.
I find it useful to make the Processes window visible;
and so when I run my app I can see that there’s a live process present and then if I navigate forwards from my app I can see that I have detached from that process and if I navigate back I can see whether I’ve attached to the same process or a different one – certainly helps me out.
Wrapping Up
This isn’t an exhaustive post. There are other things that you need to consider here like what happens on Windows 8 when your app is already running and the user re-launches it via a means like using it as a share target or searching into the app and, similarly, there are similar scenarios on Windows Phone 8 for launching apps via means other than their primary tile.
What was useful for me in writing this up was to think about the commonalities across the models and to refresh my memory of how the Phone works (and how it has changed from the original 7 to 7.5 to 8) in some slightly different way to Windows 8.
I’d also say that I’d really hope for a consistent way of doing this across the Windows and Windows Phone platforms in the future both from the point of view of making it easier to understand and also from the point of view of being able to build portable code that works in both scenarios – but, naturally, the futures isn’t mine to know about when it comes