更改配置时,MapView 在具有 Coordinator 布局的片段中崩溃

MapView crashes in fragment with Coordinator layout, when changing configuration

我的 MapViewCoordinatorLayout 自定义片段有问题。我做了一个简单的应用程序来说明这一点。我也尝试在标准 Google API 演示上执行相同的操作,但没有出现任何问题,但这可能是因为他们使用的是 MapFragment 而不是 MapView

下面,我已经上传了代码和布局。最后还粘贴了错误跟踪。

public class BlankFragment extends Fragment implements OnMapReadyCallback {

    private MapView mapView;
    private Bundle BundleForMap;

    @Override
    public void onMapReady(GoogleMap googleMap) { }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        BundleForMap = savedInstanceState;
    }

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

        mapView = (MapView) view.findViewById(R.id.map_event_mapview);
        mapView.onCreate(BundleForMap);
        mapView.getMapAsync(this);
        return view;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }

    @Override
    public void onResume() {
        super.onResume();
        mapView.onResume();
    }

    @Override
    public void onPause() {

        super.onPause();
        mapView.onPause();
    }

    @Override
    public void onDestroy() {
        mapView.onDestroy();
        super.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapView.onLowMemory();
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        mapView.onSaveInstanceState(savedInstanceState);
        super.onSaveInstanceState(savedInstanceState);
    }

}

Activity 只是调用该片段并用它替换容器视图:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        BlankFragment blankFragment = new BlankFragment();
        fragmentTransaction.replace(R.id.container, blankFragment, "");

        fragmentTransaction.commit();

    }

这是片段布局:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mapview_test.BlankFragment">

    <com.google.android.gms.maps.MapView
        android:id="@+id/map_event_mapview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/map_event_bottom_sheet"
        android:layout_height="match_parent"
        android:layout_width="match_parent" >

        <android.support.v4.widget.NestedScrollView
            android:id="@+id/bottom_sheet"
            android:layout_width="match_parent"
            android:layout_height="175dp"
            android:elevation="16dp"
            android:outlineProvider="bounds"
            android:background="@android:color/white"
            >

            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="16dp"
                android:textSize="16sp"
                android:id="@+id/testText"/>

        </android.support.v4.widget.NestedScrollView>

    </android.support.design.widget.CoordinatorLayout>

</FrameLayout>

问题显然出在 Coordinator 布局及其打包方式上。

Process: com.example.alovita.mapview_test, PID: 12989
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.alovita.mapview_test/com.example.alovita.mapview_test.MainActivity}: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: android.support.design.widget.CoordinatorLayout$SavedState
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2370)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2432)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3992)
at android.app.ActivityThread.access00(ActivityThread.java:154)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1327)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5310)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: android.support.design.widget.CoordinatorLayout$SavedState
at android.os.Parcel.readParcelableCreator(Parcel.java:2295)
at android.os.Parcel.readParcelable(Parcel.java:2245)
at android.os.Parcel.readValue(Parcel.java:2152)
at android.os.Parcel.readSparseArrayInternal(Parcel.java:2546)
at android.os.Parcel.readSparseArray(Parcel.java:1874)
at android.os.Parcel.readValue(Parcel.java:2209)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)
at android.os.BaseBundle.unparcel(BaseBundle.java:221)
at android.os.Bundle.getBundle(Bundle.java:733)
at aac.a(:com.google.android.gms.DynamiteModulesB:74)
at maps.ad.u.a(Unknown Source)
at maps.ad.R.a(Unknown Source)
at wc.onTransact(:com.google.android.gms.DynamiteModulesB:66)
at android.os.Binder.transact(Binder.java:380)
at com.google.android.gms.maps.internal.IMapViewDelegate$zza$zza.onCreate(Unknown Source)
at com.google.android.gms.maps.MapView$zza.onCreate(Unknown Source)
at com.google.android.gms.dynamic.zza.zzb(Unknown Source)
at com.google.android.gms.dynamic.zza.zza(Unknown Source)
at com.google.android.gms.maps.MapView$zzb.zzbow(Unknown Source)
at com.google.android.gms.maps.MapView$zzb.zza(Unknown Source)
at com.google.android.gms.dynamic.zza.zza(Unknown Source)
at com.google.android.gms.dynamic.zza.onCreate(Unknown Source)
at com.google.android.gms.maps.MapView.onCreate(Unknown Source)
at com.example.alovita.mapview_test.BlankFragment.onCreateView(BlankFragment.java:45)
at android.app.Fragment.performCreateView(Fragment.java:2053)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:894)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1049)
at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1869)
at android.app.Activity.performCreateCommon(Activity.java:6860)
at android.app.Activity.performCreate(Activity.java:6867)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2323)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2432) 
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3992) 
at android.app.ActivityThread.access00(ActivityThread.java:154) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1327) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5310) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699) 

这一行有问题:

mapView.onCreate(BundleForMap);

当屏幕配置改变时,这个参数显然不是null并且应用程序崩溃了。在此处传递 null 而不是 bundle 时,它​​工作正常。当我删除 CoordinatorLayout 时,应用程序运行正常。

这是我的依赖项:

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.1"

    defaultConfig {
        applicationId "com.example.mapview_test"
        minSdkVersion 22
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.2.0'
    compile 'com.android.support:support-v4:24.2.0'
    compile 'com.android.support:recyclerview-v7:24.2.0'
    compile 'com.android.support:design:24.2.0'
    compile 'com.google.android.gms:play-services-appindexing:9.4.0'
    compile 'com.google.android.gms:play-services-maps:9.4.0'
    compile 'com.google.android.gms:play-services-location:9.4.0'
}

长期以来我一直坚持这个。任何帮助将不胜感激

这似乎是一个众所周知的问题:Android Issue 6237

我已经根据这个答案实现了自己的解决方案:Android Issue 6237 #C9

实现如下(根据#C9回答):

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.

@Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        final Bundle mapViewSaveState = new Bundle(savedInstanceState);
        mapView.onSaveInstanceState(mapViewSaveState);
        savedInstanceState.putBundle("mapViewSaveState", mapViewSaveState);

        Bundle customBundle = new Bundle();
        // put custom objects if needed to customBundle

        savedInstanceState.putBundle(ARG_CUSTOM_BUNDLE, customBundle);
        super.onSaveInstanceState(savedInstanceState);
    }

然后,在 onCreate 中使用 mapViewSaveState(如果是片段,则为 onCreateView):

mapView.onCreate(savedInstanceState != null ? savedInstanceState.getBundle("mapViewSaveState") : null);