RecyclerView / MapView crashes when rotating devic

2019-04-13 04:53发布

问题:

I have a Android.Support.V4.Fragment that contains both a MapView and a RecyclerView. These are separate views in the Fragment.

The app crashes when the device is rotated:

Android.OS.BadParcelableException: ClassNotFoundException when unmarshalling: android.support.v7.widget.RecyclerView$SavedState

I am passing the lifecycle methods to the MapView as required by the docs:

private MapView mapView;
private RecyclerView myRecyclerView;
private RecyclerView.LayoutManager myLayoutManager;

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    base.OnCreateView(inflater, container, savedInstanceState);

    myRecyclerView = myRootView.FindViewById<RecyclerView>(Resource.Id.myRecyclerView);
    myLayoutManager = new LinearLayoutManager(activity, LinearLayoutManager.Horizontal, false);
    myRecyclerView.SetLayoutManager(myLayoutManager);
    myRecyclerAdapter = ...
    myRecyclerView.SetAdapter(myRecyclerAdapter);

    mapView.OnCreate(savedInstanceState);
}


public override void OnSaveInstanceState(Bundle outState)
{
    ...
    if (mapView != null) mapView.OnSaveInstanceState(outState);
    base.OnSaveInstanceState(outState);
}

If I remove the RecyclerView form the AXML it rotates correctly, if I include it the app crashes at mapView.OnCreate(savedInstanceState) why is this?

回答1:

For anyone that searches and has the same problem. This is the solution, It would appear to be a 2yr old bug.

I was able to get around it by saving the MapView's saved state on a separate Bundle and then adding it to the outgoing saved state bundle. Then in onCreate(), I would just grab the MapView's saved state from the incoming one and pass it into its onCreate() method, thus stopping the crashes.

In my case I implemented as so:

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
{
    base.OnCreateView(inflater, container, savedInstanceState);

    myRecyclerView = myRootView.FindViewById<RecyclerView>(Resource.Id.myRecyclerView);
    myLayoutManager = new LinearLayoutManager(activity, LinearLayoutManager.Horizontal, false);
    myRecyclerView.SetLayoutManager(myLayoutManager);
    myRecyclerAdapter = ...
    myRecyclerView.SetAdapter(myRecyclerAdapter);

    Bundle mapViewSavedInstanceState = savedInstanceState != null ? savedInstanceState.GetBundle("mapViewSaveState") : null;
    mapView.OnCreate(mapViewSavedInstanceState); 
}


public override void OnSaveInstanceState(Bundle outState) 
{
    if (mapView != null)
    { 
        Bundle mapViewSaveState = new Bundle(outState);
        outState.PutBundle("mapViewSaveState", mapViewSaveState);
        mapView.OnSaveInstanceState(outState);

    }
    base.OnSaveInstanceState(outState); 
}


回答2:

Tallpaul's answer didn't work for me. The solution that he linked was working good though.

public class FragmentMain extends Fragment {

    private Bundle savedInstanceState;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ... 

        this.savedInstanceState =  savedInstanceState; 
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        containerView = inflater.inflate(R.layout.fragment_main, container, false);

        //mapView bug https://code.google.com/p/gmaps-api-issues/issues/detail?id=6237#c9
        final Bundle mapViewSavedInstanceState =
            savedInstanceState != null ?  
                savedInstanceState.getBundle("mapViewSaveState") : null;

        vmGoogleMap.create( mapViewSavedInstanceState  ;


        return containerView;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {

        //mapView bug https://code.google.com/p/gmaps-api-issues/issues/detail?id=6237#c9 
        final Bundle mapViewSaveState = new Bundle(outState);
        vmGoogleMap.onSaveInstanceState(mapViewSaveState);
        outState.putBundle("mapViewSaveState", mapViewSaveState);

        super.onSaveInstanceState(outState);
    }

}