62

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)
J Avery
  • 703
  • 1
  • 5
  • 7
  • 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. – Vikram Ezhil Aug 22 '15 at 18:36

8 Answers8

85

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");
1800 INFORMATION
  • 119,313
  • 29
  • 152
  • 234
David Wasser
  • 85,616
  • 15
  • 182
  • 239
  • 3
    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 I – J Avery Feb 18 '15 at 17:55
  • thanks for those options. I had read that Bundles store the classnames, so I tried the following, and it worked: – J Avery Feb 18 '15 at 20:10
  • 10
    As your response led me to my resolve, I will give you the credit here. to send: 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"); – J Avery Feb 18 '15 at 20:16
  • 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. – David Wasser Feb 19 '15 at 10:11
  • 8
    The line `bundle.setClassLoader(.class.getClassLoader());` before calling getParcelable() did the trick for me! – Daniel Mar 04 '15 at 13:18
  • My problem was that i´ved declared my class twise in the same activity. Thank god for local history.. – Sindri Þór Sep 22 '15 at 22:48
  • 5
    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. – MandisaW Oct 26 '16 at 21:21
  • Please try Flux's solution(at the bottom), it's very simple – Na Pro Jan 12 '17 at 10:41
  • the last one solution helps me – Amos Nov 19 '18 at 04:28
  • 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. – Prince Gnakou Aug 25 '20 at 02:56
10

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.

Flux
  • 419
  • 7
  • 6
8

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");
    }
}
J Avery
  • 703
  • 1
  • 5
  • 7
5

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.

crazypeter
  • 1,028
  • 1
  • 8
  • 12
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

Ahmed Elshaer
  • 237
  • 3
  • 20
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")
marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
Blake
  • 57
  • 5
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.

Shramov
  • 41
  • 1
  • 4
0

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")
Orgazm pionerki
  • 326
  • 4
  • 11