Friday, May 18, 2012

A question about Application LifeCycle in MvvmCross (especially Mono for Android and MonoTouch)


I got asked on StackOverflow about:

I've a ViewModel which contains a Team which has a Players property which is a list of Player objects. Within TeamView the Team is deep loaded, so player data is already in the memory.
What is the best way to pass a given selected Player class instance to a PlayerView?


Here was my answer:

In general navigation, MvvmCross only allows strings to be passed between ViewModels.
The reason for this is that the navigation needs to be done at a platform level via mechanisms such as Xaml Uris or Android Intents.
For the situation you suggest, the general pattern I would typcially use is:
  • that the TeamViewModel gets the team data from the network using an injected ITeamService
  • that the TeamViewModel also uses an injected singleton ITeamCache to cache the Team
  • that the navigation happens via a call like:
this.RequestNavigate(new { teamId, playerId })
  • the PlayerViewModel then receives the TeamId and PlayerId in its constructor, and uses the ITeamCache to collect the right player
This code might look like:
 public class TeamViewModel 
     : MvxViewModel
     , IMvxServiceConsumer
 {
     public TeamViewModel(string teamId, string playerId)
     {
         var teamCache = this.GetService();
         Player = teamCache.GetPlayer(teamId, playerId);
         if (Player == null)
         {
             // todo - handle this error somehow!
         }
     }

     public Player Player { get; set; }
 }
Notice that the code above tests for whether Player is null. This is because there is a problem with your assumption "Within TeamView the Team is deep loaded, so player data is already in the memory."
The problem is that in platforms like Android and WP7, the operating system is free to remove your application from memory and to then restart it later. This is referred to as Tombstoning on WP7, but just seems to be called Killed on Android.
In these cases, then the operating system may restart your application later when the user navigates back. This restart will go direct to the activity where the user last was, and it will remember the back stack - it will then be up to your application to properly rehydrate any required objects back into memory.
Here are some very small pictures explaining this...
Android lifecycle from Xamarin docs enter image description here
For more detail, see Xamarin and MSDN

For your Team/Player case, you might be able to cope with rehydration by:
  • Implementing the ITeamCache as a file-backed object - e.g. it could use a JSON file or a SQLite database as a persistent store for the in-memory data
  • Implementing some logic in your code that refetches data from the network when needed
  • Implementing some emergency-navigate-back-home strategy in these cases - as these cases don't happen that often in many applications on modern resource rich phones.
  • Just crashing - although this isn't advisable...
It's no surprise, that many applications don't handle tombstoning very well...

Note - for small objects, your option 3 (serialization) can works well - however, this wouldn't help you with the situation where app rehydration occurs and a user then navigates back from a PlayerViewModel to a TeamViewModel.

For more on some of the recent changes on Android lifecyle within MvvmCross, seehttp://slodge.blogspot.co.uk/2012/05/android-application-initialization-and.html


No comments:

Post a Comment