Android E/Parcel﹕ Class not found when unmarshalling (only on Samsung Tab3)
Asked Answered
L

8

68

I've been unable to resolve why this error occurs, and only on a Samsung Tab3 device, running 4.4.2? It happens when my MainActivity starts another Activity, and passes a Parcelable class in the intent like so:

    private void debugTest(TestParcel cfgOptions){
        TestParcel cfgOptions = new TestParcel();
        cfgOptions.setValue(15); //just to verify

        Intent intent = new Intent(MainActivity.this, TestActivity.class);
        intent.putExtra("cfgOptions", cfgOptions);
        startActivityForResult(intent, DBG_TEST);
    }

TestActivity gets the parcelable data like so:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.test_activity);

    TestParcel cfgOptions = getIntent().getExtras().getParcelable("cfgOptions");
}

The class TestParcel:

    import android.os.Parcel;
    import android.os.Parcelable;

    public class TestParcel implements Parcelable {
    private long l_ucs_value = 0;
    private String s_rx_number = "";

    //constructor
    public TestParcel() {
        l_ucs_value = 0;
        s_rx_number = "";
    }

    public void RxNumber(String s) {
        s_rx_number = s;
    }
    public String RxNumber() {
        return s_rx_number;
    }

    //-----------------------------------------------------------------------
    public void setValue(long v){
        l_ucs_value = v;
    }
    public long getValue(){ return l_ucs_value; }


    protected TestParcel(Parcel in) {
        l_ucs_value = in.readLong();
        s_rx_number = in.readString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(l_ucs_value);
        dest.writeString(s_rx_number);
    }

    @SuppressWarnings("unused")
    public static final Parcelable.Creator<TestParcel> CREATOR = new Parcelable.Creator<TestParcel>() {
        @Override
        public TestParcel createFromParcel(Parcel in) {
            return new TestParcel(in);
        }

        @Override
        public TestParcel[] newArray(int size) {
            return new TestParcel[size];
        }
    };
}

Again, I only see this on the Samsung Tab3 device - but that's the device we need it to work on. Here's the samsung logcat:

02-18 08:05:55.393    2235-2571/? E/Parcel? Class not found when unmarshalling: com.vms.android.VersatileDEX.TestParcel
java.lang.ClassNotFoundException: com.vms.android.VersatileDEX.TestParcel
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:251)
        at java.lang.Class.forName(Class.java:216)
        at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
        at android.os.Parcel.readParcelable(Parcel.java:2097)
        at android.os.Parcel.readValue(Parcel.java:2013)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
        at android.os.Bundle.unparcel(Bundle.java:249)
        at android.os.Bundle.getString(Bundle.java:1118)
        at android.content.Intent.getStringExtra(Intent.java:5148)
        at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1467)
        at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1063)
        at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4134)
        at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:4032)
        at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2712)
        at android.os.Binder.execTransact(Binder.java:404)
        at dalvik.system.NativeStart.run(Native Method)
 Caused by: java.lang.NoClassDefFoundError: com/vms/android/VersatileDEX/TestParcel
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:251)
        at java.lang.Class.forName(Class.java:216)
        at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
        at android.os.Parcel.readParcelable(Parcel.java:2097)
        at android.os.Parcel.readValue(Parcel.java:2013)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
        at android.os.Bundle.unparcel(Bundle.java:249)
        at android.os.Bundle.getString(Bundle.java:1118)
        at android.content.Intent.getStringExtra(Intent.java:5148)
        at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1467)
        at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1063)
        at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4134)
        at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:4032)
        at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2712)
        at android.os.Binder.execTransact(Binder.java:404)
        at dalvik.system.NativeStart.run(Native Method)
 Caused by: java.lang.ClassNotFoundException: Didn't find class "com.vms.android.VersatileDEX.TestParcel" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:67)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:251)
        at java.lang.Class.forName(Class.java:216)
        at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
        at android.os.Parcel.readParcelable(Parcel.java:2097)
        at android.os.Parcel.readValue(Parcel.java:2013)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
        at android.os.Bundle.unparcel(Bundle.java:249)
        at android.os.Bundle.getString(Bundle.java:1118)
        at android.content.Intent.getStringExtra(Intent.java:5148)
        at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1467)
        at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1063)
        at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4134)
        at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:4032)
        at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2712)
        at android.os.Binder.execTransact(Binder.java:404)
        at dalvik.system.NativeStart.run(Native Method)
Laniary answered 18/2, 2015 at 17:7 Comment(1)
I had this same unmarshaling error in Samsung Tab3 and tried almost all the possible solutions including yours and none seem to solve the issue until I updated to the latest version of Android Studio 1.3.1 which finally solved the issue. Update to the latest version, clean project and rebuild it which should do the trick.Rolfrolfe
W
95

For some strange reason it looks like the class loader isn't set up properly.

Try one of the following in TestActivity.onCreate():


TestParcel cfgOptions = getIntent().getParcelableExtra("cfgOptions");

Intent intent = getIntent();
intent.setExtrasClassLoader(TestParcel.class.getClassLoader());
TestParcel cfgOptions = intent.getParcelableExtra("cfgOptions");

Bundle extras = getIntent().getExtras();
extras.setClassLoader(TestParcel.class.getClassLoader());
TestParcel cfgOptions = extras.getParcelable("cfgOptions");

Alternatively, wrap the parcelable into a bundle:

Bundle b = new Bundle();
b.putParcelable("options", cfgOptions);
Intent intent = new Intent(MDex.this, TestActivity.class);
intent.putExtra("bundle", b);

to get:

Bundle b = getIntent().getBundleExtra("bundle");
TestParcel cfgOptions = b.getParcelable("options");
Wolff answered 18/2, 2015 at 17:29 Comment(8)
I was really hoping for a success, but none of those scenarios resolved the issue. I wonder if this could truly be a Samsung specific issue? The app does not crash until I(though ILaniary
Thanks. I suppose I should have also suggested wrapping the extra in a Bundle. There are cases where wrapping custom Parcelable objects is necessary, but usually only when an external application (like AlarmManager) is involved.Wolff
The line bundle.setClassLoader(<ClassName>.class.getClassLoader()); before calling getParcelable() did the trick for me!Fillister
My problem was that i´ved declared my class twise in the same activity. Thank god for local history..Montero
I was only getting this error on our Samsung test devices - wrapping in a Bundle seems to ensure that Android's ClassLoader handles the (un)marshalling, not some custom Samsung code.Nematode
Please try Flux's solution(at the bottom), it's very simpleRational
the last one solution helps meEarthling
Also if you have multiple properties with different type each, make sure you are reading the parcel properties in the same order you wrote them into the parcel.Revolution
C
13

In my case, new Intent().putExtra(key,parcelable) which internally auto creates new bundle gives me unmarshall error I don't know why, so I had to create new bundle by myself, add the parcelable on it and add the bundle on the intent. By doing so it solves the problem.

Chartulary answered 31/12, 2015 at 14:38 Comment(1)
Thanks so much. Your solution is very simpleRational
L
9

Just trying to be more concise and clear of the answer here -

//sending a parcelable class to another activity -----------------

MyParcelableOptionsClass mpoc = new MyParcelableOptionsClass();

Bundle b = new Bundle();
b.putParcelable("options", mpoc );

Intent intent = new Intent(MyActivity.this, OtherActivity.class);
intent.putExtra("bundle", b);

startActivityForResult(intent, 1);


//getting the parcelable class from OtherActivity------------------

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.other_activity);

    Bundle b = getIntent().getBundleExtra("bundle");
    MyParcelableOptionsClass mpoc = b.getParcelable("options");
}


//returning the parcelable class back from OtherActivity -----------

 Bundle b = new Bundle();
 b.putParcelable("options", mpoc);

 Intent intent = new Intent();
 intent.putExtra("bundle", b);

 setResult(0, intent);


//and getting the parcelable class back in MyActivity --------------

onActivityResult(int requestCode, int resultCode, Intent data){
    if(null != data){
        Bundle b = data.getBundleExtra("bundle");
        MyParcelableOptionsClass mpoc = b.getParcelable("options");
    }
}
Laniary answered 18/2, 2015 at 21:51 Comment(0)
T
7

The same issue happened to me with a recent Samsung S8 phone. Creating the bundle explicitly worked for me. I used the following code, which doesn't require a string identifier for the bundle:

// Create the intent to start the activity.
Bundle bundle = new Bundle();
bundle.putParcelable("YOUR_PARCELABLE_ID", yourPacelable);
Intent intent = new Intent(context, YourActivity.class);
intent.putExtras(bundle);

And then read the parcelable back in the activity:

// In your activity, read parcelable back.
YourParcelable p = getIntent().getParcelableExtra("YOUR_PARCELABLE_ID");

I hope this helps.

Twomey answered 22/1, 2018 at 19:49 Comment(1)
Same error; only intent.putExtra("my-field", myBundle) approach works for Kotling (tested on Samsung j5, Kotlin 1.6.20).Ungual
P
1

I had same issue. In my case intent's extras had two parcealable objects with same keys. For example:

val intent = Intent()
val anotherIntent = Intent()

anotherIntent.putExtra("same_extra_key", MyParcelableObj())
intent.putExtra("same_extra_key", MyParcelableObj())

intent.putExtra("another_intent_extra_key", anotherIntent)

// ClassNotFoundError
intent.getParcelableExtra<MyParcelableObj>("same_extra_key")

You have to use different keys or getParcelableArrayListExtra method to avoid error.

intent.getParcelableArrayListExtra<MyParcelableObj>("same_extra_key")
Paloma answered 31/8, 2020 at 14:56 Comment(1)
I noticed that I have to Intents with extras with same name, one for Activity and one for the fragments inside. But the code is only failing on release mode, why would that happen? I already set minify and proguard to false and it still happens.Circumambulate
P
0

For people who are using both Java and Kotlin in your project, you may encounter this kind of error if you are creating a Parcelable Data Class in kotlin and you are using it in Java Class eg Activity or something, it seems to be an issue and its solution is just to use Java POJOs instead if kotlin data class

Practice answered 24/8, 2019 at 11:21 Comment(1)
Do you know of any reference/ticket in this regard?Thaumaturge
M
0

May be useful for people who mix Java with Kotlin.

I found an easy solution that allows using only Kotlin and without boilerplate.

val intent = Intent(this, TestActivity::class.java).apply {
    extras?.putParcellable("cfgOptions", cfgOptions)
}

startActivityForResult(intent, DBG_TEST);

And then to retrieve the value you should use:

var cfgOptions = intent?.extras?.getParcellable<TestParcel>("cfgOptions")
Masseur answered 29/8, 2019 at 17:5 Comment(0)
E
0

Just found one more cause of this Exception. For some reason, I only got it when activity was restored, but not when it was created for the first time. If your parcelable entity is kotlin data class which is child of some class, and you try to unparcel it, you may get BadParcelableException, Class not found when unmarshalling. Solution is to make such class just class, not data class.

Exhaustion answered 5/9, 2019 at 11:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.