xamarin.androidmvvmcross

MvvmCross 4.4.0, MvxAndroidBindingContextHelpers.Current() is Null when targeting API Level 31 and running on Android 12


Our Xamarin Android app relies heavily on some older components in MvvmCross 4.4.0 and so has not been updated to modern versions.

We used the guide found here to modernise just enough to get over the API 29/Android 10 hurdle: https://blog.ostebaronen.dk/2020/08/old-mvvmcross-and-android-10.html

We're now at the API 31/Android 12 hurdle and, whilst everything builds and executes fine with API 31 when running on Android 11 and below, Android 12 is crashing.

The MainActivity is initialising with a null ViewModel because the LayoutInflater (already corrected for API 29) cannot retrieve the current binding context with MvxAndroidBindingContextHelpers.Current().

Nothing in the Android 12 behaviour changes guides gives an indication as to what is causing this change. We have also reviewed changes in modern versions of the MvvmCross.Binding source and can't see any obvious changes that correct this behaviour.

This is the code in LayoutInflater.cs where the problem first surfaces:

public override View? Inflate(int resource, ViewGroup? root, bool attachToRoot)
{
    // Make sure our private factory is set since LayoutInflater > Honeycomb
    // uses a private factory.
    SetPrivateFactoryInternal();

    // Save the old factory in case we are recursing because of an MvxAdapter etc.
    IMvxLayoutInflaterHolderFactory? originalFactory = _bindingVisitor.Factory;

    try
    {
        IMvxLayoutInflaterHolderFactory? factory = null;

        // Get the current binding context
        var currentBindingContext = MvxAndroidBindingContextHelpers.Current();

        // currentBindingContext is null on Android 12, not on Android 11 and below
        if (currentBindingContext != null)
        {
            factory = FactoryFactory?.Create(currentBindingContext.DataContext);

            // Set the current factory used to generate bindings
            if (factory != null)
                _bindingVisitor.Factory = factory;
        }

        // Inflate the resource
        var view = base.Inflate(resource, root, attachToRoot);

        // Register bindings with clear key
        if (currentBindingContext != null)
        {
            if (factory != null)
                currentBindingContext.RegisterBindingsWithClearKey(view, factory.CreatedBindings);
        }

        return view;
    }
    finally
    {
        _bindingVisitor.Factory = originalFactory;
    }
}

Any insight as to potential causes of the problem would be welcome, even if it's a concrete reason why MvvmCross 4.4.0 is simply no-longer viable on Android 12.

Thanks very much.

Update: We have now successfully updated to MvvmCross 5.0.1 and the problem still remains (which we expected). Our dependency is on MvvmCross.Droid.Shared, which is removed from newer versions. Can anybody recommend a guide on migrating away from MvvmCross.Droid.Shared please, as it doesn't appear to be mentioned in the upgrade guides other than to just remove it?

Update 2: Switching out the LayoutInflater for the one from MvvmCross 9.0.1 makes no difference. We've done this simply to rule that out. The issue feels like it related more to Binding.


Solution

  • The issue was not directly related to MvvmCross, but rather a change in Android 12 behaviour that prevented initialisation in a manner that meant ViewModel binding wasn't happening despite the rest of the code executing.

    The resolution was to add some specific AndroidX initialisation lines to the AndroidManifest:

    <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup">
          <meta-data android:name="androidx.lifecycle.ProcessLifecycleInitializer" android:value="androidx.startup" />
    </provider>
    

    ...and to