Question

Some times when the activity is destroyed (not sure why, memory pressure I presume), a new activity is created, but the old view model bound to the dead activity is reused.

Activity:

[Activity( 
    LaunchMode = LaunchMode.SingleTask,
    ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
public class HomeView : MvxTabsFragmentActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        Log.Info("On HomeView created");
        base.OnCreate(bundle);
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
        Log.Info("On HomeView destroyed");
        this.HomeViewModel.CleanUp();
    }        
}

ViewModel:

public class HomeViewModel : MvxViewModel
{
    public HomeViewModel(
        IMvxMessenger messenger,
        IUserInteraction userInteraction,
        DashboardViewModel dashboardViewModel,
        AlertSettingsViewModel alertSettingsViewModel)
    {
        Log.Info("Building home view model");
    }

    public void CleanUp()
    {
        Log.Info("HomeViewModel => Clean-up");
    }       
}

App.cs:

    public override void Initialize()
    {
        this.CreatableTypes().EndingWith("ViewModel").AsTypes().RegisterAsDynamic();

        this.RegisterAppStart<HomeViewModel>();

        TaskScheduler.UnobservedTaskException +=
            (sender, eventArgs) =>
            Log.Error("An Unobserved exception has been raised by a task", eventArgs.Exception);
    }

Debug output:

On HomeView created
Building home view model
...
On HomeView destroyed
HomeViewModel => Clean-up
...
On HomeView created
[here: no "Building view model" message]

Maybe it is the SingleTask Activity ?

Is there a way (with IoC, or other) to get a fresh view model at every HomeView creation ?

EDIT:

I ran over this method on MvxActivityViewExtensions.cs

public static void OnViewCreate(this IMvxAndroidView androidView, Bundle bundle)
{
  MvxActivityViewExtensions.EnsureSetupInitialized(androidView);
  MvxActivityViewExtensions.OnLifetimeEvent(androidView, (Action<IMvxAndroidActivityLifetimeListener, Activity>) ((listener, activity) => listener.OnCreate(activity)));
  IMvxViewModel cached = Mvx.Resolve<IMvxSingleViewModelCache>().GetAndClear(bundle);
  IMvxView view = (IMvxView) androidView;
  IMvxBundle savedState = MvxActivityViewExtensions.GetSavedStateFromBundle(bundle);
  MvxViewExtensionMethods.OnViewCreate(view, (Func<IMvxViewModel>) (() => cached ?? MvxActivityViewExtensions.LoadViewModel(androidView, savedState)));
}

So would it mean my view model is cached ? How to disable this cache ?

Was it helpful?

Solution

This is covered in the Wiki in https://github.com/MvvmCross/MvvmCross/wiki/Customising-using-App-and-Setup#overriding-viewmodel-locationconstruction


By default, MvvmCross builds a new ViewModel every time one is requested and uses the CIRS sequence - Construction-Init-ReloadState-Start - to initialize that ViewModel.

If you want to override this behaviour for one or more ViewModel types, then you can do this in your App object by supplying your own IMvxViewModelLocator implementation.

For example, you could implement

public class MyViewModelLocator
  : MvxDefaultViewModelLocator
{
    private SpecialViewModel _special = new SpecialViewModel();

    public override bool TryLoad(Type viewModelType, IDictionary<string, string> parameterValueLookup,
                                 out IMvxViewModel model)
    {
        if (viewModelType == typeof(SpecialViewModel))
        {
            model = _special;
            return true;
        }
        else if (viewModelType == typeof(FooViewModel))
        {
            model = new FooViewModel(_special);
            return true;
        }

        return base.TryLoad(viewModelType, parameterValueLookup, out model);
    }
}

and could then return this in App.cs:

protected override IMvxViewModelLocator CreateDefaultViewModelLocator()
{
    return new MyViewModelLocator();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top