Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

MvvmCross: Initialize method on the first view model

An issue was raised on MvvmCross following the release of v6 where applications were breaking because they have async code in the Initialize method of the first view model. Changes in v6 mean that the first view model is effectively loaded synchronously. This change was made because applications should not do heavy lifting before displaying the first view of their application as there are platform requirements that will cause the application to terminate if it doesn’t display the first view within the appropriate time window. This change means that any code that attempts to jump to a different thread (even something like Task.Delay) will cause the fist view of the application to break.

In some scenarios this doesn’t make sense – for example if you have a splash screen Activity on Android, the first navigation can be done asynchronously because you already have a view being displayed on the screen. Here I’m going to use a simple example to demonstrate how to resolve this issue – you should only use this if you are using a splash screen for the first view of your application.

Let’s start by breaking our application by adding the following to our first view model:

public override async Task Initialize()
{
     await Task.Delay(2000);
     await base.Initialize();
}

If you make this change and attempt to run your application you’ll see a black screen (on Android – and I’m using Android because we typically have a splash Activity such as in my earlier post).

Next we’re going to fix this by overriding the MvxAppStart class to make the first navigation asynchronous:

public class CustomMvxAppStart<TViewModel> : MvxAppStart<TViewModel>
     where TViewModel : IMvxViewModel
{
     public CustomMvxAppStart(IMvxApplication application, IMvxNavigationService navigationService) : base(application, navigationService)
     {
     }

    protected override void NavigateToFirstViewModel(object hint)
     {
         NavigationService.Navigate<TViewModel>();
     }
}

Note that it’s the bold line that we’ve changed from the built in MvxAppStart class where we call NavigationService.Navigate<TViewModel>().GetAwaiter().GetResult(); which forces the navigation to be done synchronously.

We now need to make sure that our CustomMvxAppStart is used. To do this we just need to change a single line in the App.cs to use RegisterCustomAppStart instead of RegisterAppStart

RegisterCustomAppStart<CustomMvxAppStart<FirstViewModel>>();

And we’re done – running the application now will allow the application to load successfully.

Comments are closed