“BadParcelableException: ClassNotFoundException when unmarshalling ” while using Parcel.read method that has a ClassLoader as argument

前端 未结 4 1707
我寻月下人不归
我寻月下人不归 2020-12-02 10:16

Given a custom class org.example.app.MyClass implements Parcelable, I want to write a List to a Parcel. I did the marshalling with

4条回答
  •  旧巷少年郎
    2020-12-02 11:02

    You can get this error if you subclass a custom View incorrectly.

    Assume you are subclassing BottomNavigationView and you want to add saved state to the superstate in onSaveInstanceState().

    An incorrect implementation of the Parcelable boilerplate (copied from another class or a template) would look like this:

    static class State extends BaseSavedState {
    
        Bundle stateBundle;
    
        //incorrect as super state uses ClassLoaderCreator
        public static final Creator CREATOR = new Creator() {
            public State createFromParcel(Parcel in) {
                return new State(in);
            }
    
            public State[] newArray(int size) {
                return new State[size];
            }
        };
    
        State(Parcel source) {
            super(source);
            this.stateBundle = source.readBundle(getClass().getClassLoader());
        }
    
        State(Parcelable superState) {
            super(superState);
        }
    
        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeBundle(stateBundle);
        }
    }
    

    This would not work as the superstate from BottomNavigationView requires a classloader. Instead you should carefully inspect the SavedState class from BottomNavigationView and use the correct ClassLoaderCreator rather than Creator:

    static class State extends AbsSavedState {
    
        Bundle stateBundle;
    
        public static final Creator CREATOR = new ClassLoaderCreator() {
            public State createFromParcel(Parcel in, ClassLoader classLoader) {
                return new State(in, classLoader);
            }
    
            @Override
            public State createFromParcel(Parcel source) {
                return new State(source, null);
            }
    
            public State[] newArray(int size) {
                return new State[size];
            }
        };
    
        State(Parcel source, ClassLoader classLoader) {
            super(source, classLoader);
            this.stateBundle = source.readBundle(classLoader);
        }
    
        State(Parcelable superState) {
            super(superState);
        }
    
        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeBundle(stateBundle);
        }
    }
    

    Note that extending android.support.v4.view.AbsSavedState may be a better choice than BaseSavedState or android.view.AbsSavedState since it will allow you to pass a class loader to the superclass:

    SavedState(Parcel source, ClassLoader classLoader) {
        super(source, classLoader); //available in android.support.v4.view.AbsSavedState
        this.stateBundle = source.readBundle(classLoader);
    }
    

提交回复
热议问题