One piece of feedback we hear from Windows Phone developers is that "tombstoning is hard," but there are many ways of interpreting that statement and we'd like to understand it more. We have some theories about what might be hard, but I don't want to skew any results by mentioning them here.
If you have an opinion on tombstoning in Windows Phone 7 - good or bad - please leave a comment and be as detailed as you can in the reply so we can better understand the feedback.
P.S. I'm joking about the penny.
Steve, "tombstoning" in this case refers to the application lifecycle of Windows Phone apps... I guess I should add that to the post! Thanks!
To me what makes it hard it not so much the tombstoning process - it's more the fact that I have to do it.
Example: I want to grab a picture with the camera. This leaves the app, and I would have to save all settings and state of the app. but here's what gets weird: Some things automatically gets restored: For instance the current page, or often parts of the state of a page (but far from everything). I would have to save a bunch of data to IsolatedStorage, although not everything. I usually just dump my entire app-model, so that's not really such a big issue to me, but still... I had to go through a lot to get that set up in the first place.
Add to that that there are things I can't just "dump" to IsolatedStorage, because not everything is serializable.
I get that when I leave an app I should save stuff, for instance remember username/passwords etc. I don't get why I need to do all this if I briefly leave the app and come back using back button. (ie answer a call, use camera, check my calendar etc). It should just pause the app, and not try to serialize state or anything.
Basically I think I shouldn't have to do ANYTHING until my app is about to get completely killed (and in this case only if I want to remmeber user settings etc). Having these two "modes" , ie "full" shutdown and "temporary" shutdown is confusing. Why are there two? I say: Simplify this pattern.
Another confusing thing (and an often reason for bugs - even in Microsofts own controls) is when I leave an app, and quickly hit the back button (happens a lot because search button is too easy to hit). Apparently when this happens, it's going into some "weird" kind of half-way tombstone/restore process. Its hard to test and can give some really hard to track down and hard to reproduce bugs. Again: Don't give me all these different kind of states an app can be in. Simpllify, simplify, simplify.
Tombstoning isn't necessarily 'hard', but it's more complicated than it needs to be.
I guess it's works a bit like ASP.NET session state, with manual resumption, but it's not a stateless web app so app architecture doesn't fit that model.
Perhaps something like a [Persist] attribute would be helpful?
Hey Peter. I haven't found tombstoning particularly hard. Verbose perhaps, but not hard.
If developers are finding tombtsoning hard or verbose, I'd point them at the excellent Caliburn Micro MVVM framework (Bing it), which handles persistence for you through a simple decorator on a View Model property.
I don't think that it's too hard, but there are many pain points:
1) Knowing about this, as most developers will start without implementing tombstoning (in simpler apps you will not notice that it's missing)
2) Actual implementation can be a bit messy - partially this should be implemented in App.xaml.cs and partially in pages OnNavigate* method
3) App having two startup workflows (for starting and re-activating) makes developement slower, and frameworks like CaliburnMicro help simplify this
4) Increased cost of testing these two paths for every page
I don't mind the tombstoning so much as having better support for it.
There should be a good way to serialize out the state of a ViewModel... e.g. a viewmodel base class that has support plus automatic save and load functions to isolated storage.
There should be an "after loaded" event because doing anything of interested in the Loaded event is not really advisable... winforms added a "Shown" event, perhaps that could be added.
There should also be a better way to test the Trial apis because the show marketplace task api tombstones your app and you need to be able to test your app when it has been resurrected after someone has bought it.
I wish that the control model was plugged into tombstoning better. Namely, the intrinsic controls like TextBox and ScrollViewer should tombstone their state by default, and be able to activate as they were without user intervention.
In a perfect world; there are hacks to do this today, but it's really inconsistent as an app user as a result.
I generally like it. What I think throws people off (and I didn't really understand it myself until your post in the App Hub forums earlier) is that a page's constructors might never run when coming back to it. Unless you read the documentation really, really closely, it's very easy to miss that.
I also think that the structuring itself leads to confusion about that. There's Launching, Closing, Activated, and Deactivated. Deactivated is not synonymous with tombstoning though it's very easy to conclude that deactivated == tombstoning. Instead tombstoning is (if I'm reading it correctly) something that can (but does not have to) happen while an application is deactivated. If it is tombstoned then the constructors run and Activated is called. If not then the constructors do not run and Activated is called.
So in effect there are two different kinds of "Activated" - one with constructors and one without. Only you never actually know which one you're in and the kind that's most likely to cause problems (not tombstoned and thus the constructors don't run (and I assume that includes the page constructors for the particular page the user was on)) is also the kind that's less common and can only be triggered and thus only be tested through, e.g., jamming start and back in rapid succession. I think it would probably serve everyone better if the constructors always ran, though I suppose that there are performance implications that weigh against that.
And then once you do know that there's a special activated path sans constructors, the question then becomes what data dies on deactivated and what survives? Are value types reset to their default values? Do event handlers remain intact? Does a Silverlight page automatically undergo a measurement and layout cycle when returning or does that need to be triggered again (and what effect, if any, does that have on any data-binding)?
When tombstoning doesn't occur Deactivated happens but the Loaded even never fires (since the constructor never runs). This might be a source of many problems that people face since, absent lazy loading, the Loaded event is where most developers who have learned enough that they avoid putting complex, time-consuming operations like I/O into the page constructor would in turn put it into the Loaded event.
Then there's the fact that it's quite simple to produce an infinite "Resuming..." loop. Create a Silverlight for Windows Phone 7 Application. Build it. Run it. Press Start and then Back in rapid succession. Repeat this process several times and you are certain to eventually watch the emulator/device try to resume while Visual Studio tells you "The program ' taskhost.exe: Managed' has exited with code 0 (0x0)." and reverts to non-debugging mode. But the phone (or emulator) will continue to insist that it's resuming something and will keep doing that ad infinitum unless you either press Start or Search or else power off the phone.by holding the power button down until it shuts off. I had an application resuming in the emulator for the past 5 minutes or so. At this point the indefinite progress bar has actually stopped animating and the five dots are just sitting in the middle of the window. Pressing Start and then Back again caused it to resume (so I assume that it had just gone into the emulator's equivalent of the lock screen - having just left it sit for another ~5 minutes it did the same thing though this time only one of the dots was visible at the left). This is essentially a vanilla, from the "Windows Phone Application" template app; the only thing I added was a Loaded event handler to the MainPage and three System.Diagnostic.Debug.WriteLine calls (one each in App.Application_Activated, App.Application_Deactivated, and MainPage.PhoneApplicationPage_Loaded just to confirm that Loaded didn't fire on a rapid Start-Back cycle). This is using the emulator image from the January tools update though I had seen the same behavior in the RTM emulator and see it on my phone itself too (an LG-C900 (Quantum) which has not yet had the pre-NoDo update).
Between Loaded only firing sometimes and the infinite resuming bug, I can see it being easy to get frustrated with it. I generally think it's a nice structure, though if it could be tweaked somehow to let developers know whether or not the constructor and Loaded and any other events that happen during the page construction process run that would be nice. It'd be interesting to me to see if there's something common to people who dislike it the most. I don't really use MVVM, for instance, and tend to rely on code-behind a lot more than XAML-based data binding. I know I should use Blend more and that it's a really nice tool, but I think I've started it less than a dozen times and have never done anything of substance with it. Maybe there's no correlation, but it's worth investigating. Anyway, keep up the great work! It's been nice seeing you posting on the forums - I've already learned several things from your posts there (e.g. that the constructors don't always run and thus that Loaded doesn't always run).
Although I don't think I've publicly complained about tombstoning, I do agree that it has issues. To me, the biggest problem with tombstoning is that it's simply tedious, even superfluous. I feel that, as a developer, my time is better spent working on the core functionality of my apps rather than worrying about saving and restoring state, what actions are allowed at which points in the execution cycle, and so forth. I don't understand why the runtime can't take care of this whole thing automatically.
Besides that, there's also uncertainty around how best to implement tombstoning in the context of MVVM, since the proper suspend/resume events have to be forwarded on to the model in some organized manner. (Please focus on the first part of this post more than this part)
Peter, I believe half the challenge here is the way that it is explained/taught to developers. Most of the time I hear tombstoning explained in terms of Activated and Deactivated events. This leads developers to put logic into these events to save state etc. When I present on tombstoning I focus on the OnNavigatedTo and OnNavigatingFrom methods and get developers to save and restore page state in these methods. If they do this it solves 90% of the tombstoning challenge.
I don't find it hard to do - what kind of problems are you hearing about?
From my experience if you use MVVM light and serialize the ViewModels with Mike Talbot's serializer, tombstoning is a piece of cake. However if you code the quick and dirty way with events "hardwired" to the .xaml.cs and no proper separation of concerns, it quickly becomes a mess and difficult to make it work well even for simple apps.
This may not be so bad as it forces the developer to properly structure the app, but I can see the difficulty for someone in the learning phase.
Regardless, one thing I've found it difficult is handling textbox focus: it's rather hard to restore focus to the proper element after activation (so that the keyboard is displayed again). It's a detail and I never failed certification because of this, but I've often faced this situation.
From what I experimented, the major difficulty to handle tombstoning is the break in the application's flow. Your application is resumed on the last page, it can be any page of any process of the application. Yet, all the vars (which are supposed to be set in the previous steps of the process) are reset. It forces the developers to learn how to handle application's state in a more global way, while WPF and Silverlight are designed to be used on a more "page centric" way.
I don't think it is hard. It just happens that you always forget one thing or the other and break everything :D
But I think tombstoning is something that only complex applications should have to handle themselves. I wonder why DataContract isn't just an opt-out model and tombstoning would just save the app object and the current page.