Search code examples
xamarin.androidmvvmcrosssupportmapfragment

SupportMapFragment causes exception on orientation change


The following code works fine in a single orientation but as soon as the orientation changes it causes an exception:

using Android.App;
using Android.Content.PM;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.OS;
using Android.Support.V4.App;
using Cirrious.MvvmCross.Droid.Fragging;
using System;
using System.Collections.Generic;
using System.Drawing;

namespace Demo.Droid.Views
{
    [Activity(Label = "View for MapViewModel", Theme = "@android:style/Theme.NoTitleBar", ConfigurationChanges = ConfigChanges.Orientation)]
    public class MapView : MvxFragmentActivity
    {
        private SupportMapFragment _mapFragment;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.MapView);

            InitMapFragment();
        }

        private void InitMapFragment()
        {
            _mapFragment = SupportFragmentManager.FindFragmentByTag("map") as SupportMapFragment;
            if (_mapFragment == null)
            {
                GoogleMapOptions mapOptions = new GoogleMapOptions()
                    .InvokeMapType(GoogleMap.MapTypeNormal)
                    .InvokeZoomControlsEnabled(false)
                    .InvokeCompassEnabled(true);

                FragmentTransaction fragTx = SupportFragmentManager.BeginTransaction();
                _mapFragment = SupportMapFragment.NewInstance(mapOptions);

                fragTx.Add(Resource.Id.map, _mapFragment, "map");
                fragTx.Commit();
            }
        }
    }
}

If I comment out the InitMapFragment in OnCreate then the map loads and rotates correctly, so it seems it is something to do with SupportMapFragment.

The layout file contains:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/white">
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="0.1"
        android:background="@drawable/nav_bar_background"
        android:id="@+id/bartop">
    </RelativeLayout>
    <fragment
        class="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.8"
        android:id="@+id/map" />
    <RelativeLayout
        android:orientation="horizontal"
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="0.1"
        android:id="@+id/barbottom"
        android:layout_alignParentBottom="true"
        android:background="@drawable/nav_bar_background">
    </RelativeLayout>
</LinearLayout>

Debugging output just shows 'An unhandled exception occured.' but the device log shows:

android.view.InflateException: Binary XML file line #1: Error inflating class fragment
(raw stack trace not found)
Caused by:
java.lang.IllegalStateException: Fragment com.google.android.gms.maps.SupportMapFragment did not create a view.

Solution

  • I'm still not sure of the cause of the error, but changing the fragment to a FrameLayout in the XML, and then adding the fragment programmatically fixes it.

    using Android.App;
    using Android.Content.PM;
    using Android.Gms.Maps;
    using Android.Gms.Maps.Model;
    using Android.OS;
    using Android.Support.V4.App;
    using Cirrious.MvvmCross.Droid.Fragging;
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    
    namespace Demo.Droid.Views
    {
        [Activity(Label = "View for MapViewModel", Theme = "@android:style/Theme.NoTitleBar", ConfigurationChanges = ConfigChanges.Orientation)]
        public class MapView : MvxFragmentActivity
        {
            private SupportMapFragment _mapFragment;
    
            protected override void OnCreate(Bundle bundle)
            {
                base.OnCreate(bundle);
    
                _mapFragment = new SupportMapFragment();
                var fragmentTx = this.SupportFragmentManager.BeginTransaction();
                fragmentTx.Add(Resource.Id.mapFrame, _mapFragment);
                fragmentTx.Commit();
    
                SetContentView(Resource.Layout.MapView);
            }
        }
    }
    

    with layout file:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:local="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@android:color/white">
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="0.1"
            android:background="@drawable/nav_bar_background"
            android:id="@+id/bartop">
        </RelativeLayout>
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.8"
            android:id="@+id/mapFrame" />
        <RelativeLayout
            android:orientation="horizontal"
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="0.1"
            android:id="@+id/barbottom"
            android:layout_alignParentBottom="true"
            android:background="@drawable/nav_bar_background">
        </RelativeLayout>
    </LinearLayout>