I have an Android application in which I add one more enum:
public enum RootNavigationOption {
HOME(R.string.home, R.drawable.ic_home), SETTINGS(R.string.settings, R.drawable.ic_settings), LOGOUT(
R.string.logout_label, R.drawable.ic_logout);
private int navigationOptionLabelResId;
private int navigationOptionImageResId;
private RootNavigationOption(int navigationOptionLabelResId, int navigationOptionImageResId) {
this.navigationOptionLabelResId = navigationOptionLabelResId;
this.navigationOptionImageResId = navigationOptionImageResId;
}
public int getNavigationOptionLabelResId() {
return navigationOptionLabelResId;
}
public int getNavigationOptionImageResId() {
return navigationOptionImageResId;
}
public static int getValuePosition(RootNavigationOption filterOption) {
int idx = 0;
for (RootNavigationOption navigationOptionIter : values()) {
if (navigationOptionIter.equals(filterOption)) {
return idx;
}
idx++;
}
return 0;
}
}
I put in this enum and placed it in couple of intent bundles for communication to my main activity. I already have one more such enum
in my solution, which does not cause any problems. However, when I run my application with this new enum
being defined, it immediately crashes with:
java.lang.RuntimeException: Parcelable encounteredClassNotFoundException reading a Serializable object (name = com.pack1.pack2.pack3.helpers.RootNavigationOption)
at android.os.Parcel.readSerializable(Parcel.java:2219)
at android.os.Parcel.readValue(Parcel.java:2064)
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.app.ActivityOptions.<init>(ActivityOptions.java:310)
at com.android.server.am.ActivityRecord.updateOptionsLocked(ActivityRecord.java:668)
at com.android.server.am.ActivityStack.startActivityLocked(ActivityStack.java:1778)
at com.android.server.am.ActivityStackSupervisor.startActivityUncheckedLocked(ActivityStackSupervisor.java:1769)
at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1249)
at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:741)
at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3118)
at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3104)
at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:135)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2071)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
Caused by: java.lang.ClassNotFoundException: com.pack1.pack2.pack3.helpers.RootNavigationOption
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:251)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2262)
at java.io.ObjectInputStream.readEnumDescInternal(ObjectInputStream.java:1553)
at java.io.ObjectInputStream.readEnumDesc(ObjectInputStream.java:1534)
at java.io.ObjectInputStream.readEnum(ObjectInputStream.java:1579)
at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:768)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1981)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1938)
at android.os.Parcel.readSerializable(Parcel.java:2213)
... 16 more
Caused by: java.lang.NoClassDefFoundError: com/pack1/pack2/pack3/helpers/RootNavigationOption
... 26 more
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.pack1.pack2.pack3.helpers.RootNavigationOption" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
... 26 more
I am not able to find the root casue of the problem. I also considered the following posts, without any result:
- post1 - i am not using any cusotmclass loaders.
- post2 - i am running the application directly from ADT, no proguard involved.
Also I have:
- checked my classes in the
bin
folder and the needed class is in there. - decompiled the ready apk with apktool and the respective smali is in there too
EDIT
Now I am definitely sure that the exception is actually caused by putting the enum value in a bundle used to start the activity, although these lines are not mentioned in the stacktrace:
Bundle activityOptions = new Bundle();
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME);
Intent intent = new Intent(this, MainActivity.class);
I have changed the logic of my application to not use this enum value in Bundle
only e.g. as method parameter and now it runs without any exceptions. Does anyone have a clue why this happens?
I also place a bounty on the question now, because I am more perplexed.
I believe the problem lies on Android using multiple ClassLoader
You can try setting the class loader before
getSerializable()
Android E/Parcel﹕ Class not found when unmarshalling (only on Samsung Tab3)
Actually I would suggest not to use serializable, and implements your own parcellable.
As I suggested in my comments (assuming that Constants.VIEW_MODE is a String key):
EDIT:
Hmmm..so the public constructor is not working as per documentation. Shocking. Maybe we can force a change using this another method: http://developer.android.com/reference/android/os/Bundle.html#setClassLoader(java.lang.ClassLoader)
Try this instead and let me know what happens:
Looks like Android is unbundling on another process onto which the intent is passed and tried to be processed, where your enum doesn't live; read over: Passing enum or object through an intent (the best solution) for more information.
Simply use the enum ordinal as extra using
Enum.ordinal()
; additionally, this should make yourRootNavigationOption.getValuePosition()
obsolete.Example:
Later in your MainActivity (or similar):
While the ordinals approach works, I would advise being more explicit about the values. This does add a bit more code to implement, but it makes your code more readable and explicit to protect against possible future issues like reordering or inserting new values in the middle of the list.
This can then be used like so: