添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

"BadParcelableException: ClassNotFoundException when unmarshalling <myclass>" while using Parcel.read method that has a ClassLoader as argument

Ask Question

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

 List<MyClass> myclassList = ...
 parcel.writeList(myclassList);

whenever I try to unmarshall the class with

 List<MyClass> myclassList = new ArrayList<MyClass>();
 parcel.readList(myclassList, null);

there is an "BadParcelableException: ClassNotFoundException when unmarshalling org.example.app.MyClass" exception.

What is wrong here? Why is the class not found?

I got this error in a different context - calling bundle.keySet() on a bundle that contained a Parcelable. When running an individual test class against the code in question, it passed, but running the entire Test suite resulted in the BadParcelableException. The "fix" was to do bundle.setClassloader(MyClass.class.getClassLoader()) before bundle.keySet(). – Stan Kurdziel May 22, 2015 at 22:17 Does this answer your question? BadParcelableException: ClassNotFoundException when unmarshalling – m0skit0 Sep 3, 2021 at 7:57

Don't unmarshall a custom class (i.e. one provided by your application and not by the Android framework) with the framework class loader that is used when you give null as the ClassLoader argument. Use the application class loader:

parcel.readList(myclassList, getClass().getClassLoader());

Whenever a Parcel.read*() method also has a ClassLoader as an argument (e.g. Parcel.readList(List outVal, ClassLoader loader)) and you want to read an application class from a Parcel, use the application class loader that can be retrieved with getClass().getClassLoader().

Background: Android comes with two class loaders: the system class loader, that is able to load all system classes but the ones provided by your application; and the application class loader, which has set the system class loader as its parent and therefore is able to load all classes. If you give null as the class loader, Parcel.readParcelableCreator() will use the framework class loader, causing a ClassNotFoundException.

Thanks to alexanderblom for providing the hint that led me on the right track.

What is the reason this does not occur 100% of times? I am getting this on some user devices but cannot reproduce on my end. – Arka Prava Basu Nov 5, 2020 at 15:59

I believe a more correct form of this would be:

List<MyClass> myclassList = new ArrayList<MyClass>();
parcel.readList(myclassList, MyClass.class.getClassLoader());

Because here you are explicitly using the class loader for the List's generic type.

That's basically the same as my answer. There is no difference between MyClass.class and getClass(), both return the same class object since getClass() is called within MyClass. Also, you could use any class here, as long as it's an custom class and not one provided by the framework. – Flow Jan 29, 2014 at 8:10 I did not say you were incorrect, just that this form might be more appropriate. Also consider that you are making an additional method call to getClass() that is not necessary when you reference the class statically. – Tanner Perrien Nov 24, 2014 at 20:36

I have faced the same problem and instead of parcleable I used bundle

intent.setExtrasClassLoader(getClassLoader());
/* Send optional extras */
Bundle bundle = new Bundle();
bundle.putParcelable("object", mObject);
bundle.putString("stringVal", stringVal);
intent.putExtra("bundle",bundle);

And in my intent class I used this to retrieve the value:

Bundle oldBundle = intent.getBundleExtra("bundle");
ResultReceiver receiver = oldBundle.getParcelable("object");
String stringVal = oldBundle.getString("stringVal");
intent.setExtrasClassLoader(getClassLoader());

Hope it will be helpful for some.

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<State> CREATOR = new Creator<State>() {
        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<State> CREATOR = new ClassLoaderCreator<State>() {
        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);
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.