Mvvmcross: The async loading in the Initialize method of the first viewmodel for UWP

Created on 23 Sep 2018  路  8Comments  路  Source: MvvmCross/MvvmCross

馃敊 Regression

We already have some discussions regarding the async loading in the Initialize method of the viewmodel. According to the PR #2866 , the Android project should work, but UWP can't.

Old (and correct) behavior

With the previous version, we can create a CustomMvxAppStart class to support an async loading in the Initialize method: https://nicksnettravels.builttoroam.com/post/2018/04/19/MvvmCross-Initialize-method-on-the-first-view-model.aspx

Current behavior

Now the Android project doesn't need to create a new CustomMvxAppStart class in the Core project. But it should uniform the behaviour for all the platforms.

Reproduction steps

Create a new solution including Xamarin.Android, Xamarin.UWP and Xamarin.Core. In the FirstViewModel, use some async codes like this:

public override async Task Initialize()
        {
            // Async initialization, YEY!
            await base.Initialize();
            await GetPostsAsync();
        }

In the App.cs in the Core project, register the FirstViewModel:

    public class App : MvxApplication
    {
        public override void Initialize()
        {
            CreatableTypes()
                .EndingWith("Service")
                .AsInterfaces()
                .RegisterAsLazySingleton();
            RegisterAppStart<PostListViewModel>();
        }
    }

The Android project works, but the UWP can't. I didn't test it for iOS and the other platforms. Thanks.

Configuration

Version: 6.2

Platform:

  • [ ] :iphone: iOS
  • [X ] :robot: Android
  • [ ] :checkered_flag: WPF
  • [X ] :earth_americas: UWP
  • [ ] :apple: MacOS
  • [ ] :tv: tvOS
  • [ ] :monkey: Xamarin.Forms
uwp bug up-for-grabs

Most helpful comment

I can confirm this problem exists in WPF too. Awaiting navigation to the first view model will froze the app. The only workaround I could find is that creating a custom AppStart and not awaiting the navigattion.

All 8 comments

@yanxiaodi I'm not sure I understand what you mean by this issue. There is no regression from what I can see - all platforms can take advantage of the async support for Initialize. However, Android is the only one that currently takes advantage of this. If you want to do async work, you can still specify a CustomMvxAppStart. Can you explain your issue more please

I mean I don't need the CustomMvxAppStart for Android, but it is still necessary for UWP. There is only one Core project. Can I use a uniform way for all the platforms? Thanks.

My point is that this isn't a bug, it's just that we don't provide default support within UWP for async startup

Ok. I got it. Thank you very much.

Sorry @nickrandolph I have created the CustomMvxAppStart for UWP but it doesn't work if I put an async method in the Initialize method. Here is my code of the first viewmodel:

    public class FirstViewModel : MvxViewModel
    {
        public override async Task Initialize()
        {
            await base.Initialize();
            await Task.Delay(1000);
        }
    }

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

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

Register it in the App class in the core porject:

    public class App : MvxApplication
    {
        public override void Initialize()
        {
            CreatableTypes()
                .EndingWith("Service")
                .AsInterfaces()
                .RegisterAsLazySingleton();
            RegisterCustomAppStart<CustomMvxAppStart<FirstViewModel>>();
        }

    }

The first view can't show correctly. The app is frozen.

I know you mean that the first view should be sync, but that means I need to create a sync SplashScreenView for both Android and UWP. But there is already a SplashScree class in the Android. That makes users confused.

I am experiencing this issue with iOS.

This works on Android and iOS:

protected override Task NavigateToFirstViewModel(object hint = null)
{
    var tcs = new TaskCompletionSource<bool>();
    Task.Run(async () => tcs.SetResult(await _authenticationService.IsFirstTime()));

    if (tcs.Task.Result)
    {
        _navigationService.Navigate<OnBoardingViewModel>().GetAwaiter().GetResult();
    }
    else
    {
        _navigationService.Navigate<TabsRootViewModel>().GetAwaiter().GetResult();
    }

    return tcs.Task;
}

This only works on Android. On iOS it gets stuck on the launch screen and doesn't get past setting the isFirstTime variable:

protected override async Task NavigateToFirstViewModel(object hint = null)
{
    var isFirstTime = await _authenticationService.IsFirstTime();

    if (isFirstTime)
    {
        _navigationService.Navigate<OnBoardingViewModel>().GetAwaiter().GetResult();
    }
    else
    {
        _navigationService.Navigate<TabsRootViewModel>().GetAwaiter().GetResult();
    }
}

I can confirm this problem exists in WPF too. Awaiting navigation to the first view model will froze the app. The only workaround I could find is that creating a custom AppStart and not awaiting the navigattion.

I found it only on Android and don't see it on iOS. Waiting an async method in NavigateToFirstViewModel hangs. I suspec that method isn't itself being awaited.

Was this page helpful?
0 / 5 - 0 ratings