Android "java.lang.RuntimeException: Parcelable encounteredClassNotFoundException reading a Serializable object"
Android "java.lang.RuntimeException: Parcelable encounteredClassNotFoundException reading a Serializable object"
我有一个 Android 应用程序,我在其中添加了一个枚举:
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;
}
}
我放入了这个枚举并将其放入几个意图包中以便与我的主要 activity 通信。我的解决方案中已经有一个这样的 enum
,这不会导致任何问题。但是,当我 运行 我的应用程序定义了这个新的 enum
时,它立即崩溃并显示:
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
我找不到问题的根本原因。我还考虑了以下帖子,没有任何结果:
- post1 - 我没有使用任何 cusotmclass 装载机。
- post2 - 我 运行 直接从 ADT 安装应用程序,不涉及 Proguard。
我还有:
- 在
bin
文件夹中检查了我的 classes,需要的 class 就在那里。
- 用 apktool 反编译了准备好的 apk,相应的 smali 也在那里
编辑
现在我确定异常实际上是由于将枚举值放入用于启动 activity 的包中引起的,尽管堆栈跟踪中没有提到这些行:
Bundle activityOptions = new Bundle();
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME);
Intent intent = new Intent(this, MainActivity.class);
我已经更改了我的应用程序的逻辑,以便仅在 Bundle
中不使用此枚举值,例如作为方法参数,现在它 运行s 没有任何例外。有谁知道为什么会发生这种情况?
我现在也悬赏这个问题,因为我比较困惑
正如我在评论中所建议的(假设 Constants.VIEW_MODE 是一个字符串键):
//Inside an activity or use getApplicationConext().getClassLoader()
ClassLoader loader = this.getClassLoader();
Bundle activityOptions = new Bundle(loader);
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME);
编辑:
Hmmm..所以 public 构造函数没有按照文档工作。 震惊。
也许我们可以使用另一种方法强制更改:http://developer.android.com/reference/android/os/Bundle.html#setClassLoader(java.lang.ClassLoader)
试试这个,让我知道会发生什么:
Bundle activityOptions = new Bundle();
activityOptions.setClassLoader(RootNavigationOption.class.getClassLoader());
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME);
我认为问题在于 Android 使用多个 ClassLoader
您可以尝试在 getSerializable()
之前设置 class 加载器
bundle.setClassLoader(getClass().getClassLoader());
其实我建议不要使用serializable,自己实现parcellable。
看起来 Android 正在将意图传递到另一个进程并尝试对其进行处理,而您的枚举不存在;仔细阅读:Passing enum or object through an intent (the best solution) 了解更多信息。
简单地使用枚举序号作为额外使用 Enum.ordinal()
;此外,这应该会使您的 RootNavigationOption.getValuePosition()
过时。
示例:
final Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(Constants.VIEW_MODE, RootNavigationOption.SETTINGS.ordinal());
稍后在您的 MainActivity (或类似的):
final int defaultViewModeOrdinal = RootNavigationOption.HOME.ordinal();
final int viewModeOrdinal = getIntent().getIntExtra(Constants.VIEW_MODE, defaultViewModeOrdinal);
final RootNavigationOption viewMode = RootNavigationOption.values()[viewModeOrdinal];
虽然序数方法有效,但我建议更明确地说明值。这确实添加了更多的代码来实现,但它使您的代码更具可读性和明确性,以防止将来可能出现的问题,例如在列表中间重新排序或插入新值。
public enum RootNavigationOption {
HOME(0, R.string.home, R.drawable.ic_home),
SETTINGS(1, R.string.settings, R.drawable.ic_settings),
LOGOUT(2, R.string.logout_label, R.drawable.ic_logout);
// Note the added code instance variable here, used in the constructor as well.
private final int code;
private final int navigationOptionLabelResId;
private final int navigationOptionImageResId;
private RootNavigationOption(int code,
int navigationOptionLabelResId,
int navigationOptionImageResId) {
this.code = code;
this.navigationOptionLabelResId = navigationOptionLabelResId;
this.navigationOptionImageResId = navigationOptionImageResId;
}
public int getNavigationOptionLabelResId() {
return navigationOptionLabelResId;
}
public int getNavigationOptionImageResId() {
return navigationOptionImageResId;
}
public int getCode() {
return code;
}
public static RootNavigationOption fromCode(int code) {
switch(code) {
case 0:
return HOME;
case 1:
return SETTINGS;
case 2:
return LOGOUT;
default:
throw new RuntimeException(
"Illegal RootNavigationOption: " + code);
}
}
}
然后可以这样使用:
// Put
Bundle bundle = new Bundle();
bundle.putInt("key", RootNavigationOption.HOME.getCode());
// Get
RootNavigationOption rootNavigationOption = RootNavigationOption.fromCode(bundle.getInt("key"));
我有一个 Android 应用程序,我在其中添加了一个枚举:
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;
}
}
我放入了这个枚举并将其放入几个意图包中以便与我的主要 activity 通信。我的解决方案中已经有一个这样的 enum
,这不会导致任何问题。但是,当我 运行 我的应用程序定义了这个新的 enum
时,它立即崩溃并显示:
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
我找不到问题的根本原因。我还考虑了以下帖子,没有任何结果:
- post1 - 我没有使用任何 cusotmclass 装载机。
- post2 - 我 运行 直接从 ADT 安装应用程序,不涉及 Proguard。
我还有:
- 在
bin
文件夹中检查了我的 classes,需要的 class 就在那里。 - 用 apktool 反编译了准备好的 apk,相应的 smali 也在那里
编辑
现在我确定异常实际上是由于将枚举值放入用于启动 activity 的包中引起的,尽管堆栈跟踪中没有提到这些行:
Bundle activityOptions = new Bundle();
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME);
Intent intent = new Intent(this, MainActivity.class);
我已经更改了我的应用程序的逻辑,以便仅在 Bundle
中不使用此枚举值,例如作为方法参数,现在它 运行s 没有任何例外。有谁知道为什么会发生这种情况?
我现在也悬赏这个问题,因为我比较困惑
正如我在评论中所建议的(假设 Constants.VIEW_MODE 是一个字符串键):
//Inside an activity or use getApplicationConext().getClassLoader()
ClassLoader loader = this.getClassLoader();
Bundle activityOptions = new Bundle(loader);
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME);
编辑:
Hmmm..所以 public 构造函数没有按照文档工作。 震惊。 也许我们可以使用另一种方法强制更改:http://developer.android.com/reference/android/os/Bundle.html#setClassLoader(java.lang.ClassLoader)
试试这个,让我知道会发生什么:
Bundle activityOptions = new Bundle();
activityOptions.setClassLoader(RootNavigationOption.class.getClassLoader());
activityOptions.putSerializable(Constants.VIEW_MODE, RootNavigationOption.HOME);
我认为问题在于 Android 使用多个 ClassLoader
您可以尝试在 getSerializable()
bundle.setClassLoader(getClass().getClassLoader());
其实我建议不要使用serializable,自己实现parcellable。
看起来 Android 正在将意图传递到另一个进程并尝试对其进行处理,而您的枚举不存在;仔细阅读:Passing enum or object through an intent (the best solution) 了解更多信息。
简单地使用枚举序号作为额外使用 Enum.ordinal()
;此外,这应该会使您的 RootNavigationOption.getValuePosition()
过时。
示例:
final Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(Constants.VIEW_MODE, RootNavigationOption.SETTINGS.ordinal());
稍后在您的 MainActivity (或类似的):
final int defaultViewModeOrdinal = RootNavigationOption.HOME.ordinal();
final int viewModeOrdinal = getIntent().getIntExtra(Constants.VIEW_MODE, defaultViewModeOrdinal);
final RootNavigationOption viewMode = RootNavigationOption.values()[viewModeOrdinal];
虽然序数方法有效,但我建议更明确地说明值。这确实添加了更多的代码来实现,但它使您的代码更具可读性和明确性,以防止将来可能出现的问题,例如在列表中间重新排序或插入新值。
public enum RootNavigationOption {
HOME(0, R.string.home, R.drawable.ic_home),
SETTINGS(1, R.string.settings, R.drawable.ic_settings),
LOGOUT(2, R.string.logout_label, R.drawable.ic_logout);
// Note the added code instance variable here, used in the constructor as well.
private final int code;
private final int navigationOptionLabelResId;
private final int navigationOptionImageResId;
private RootNavigationOption(int code,
int navigationOptionLabelResId,
int navigationOptionImageResId) {
this.code = code;
this.navigationOptionLabelResId = navigationOptionLabelResId;
this.navigationOptionImageResId = navigationOptionImageResId;
}
public int getNavigationOptionLabelResId() {
return navigationOptionLabelResId;
}
public int getNavigationOptionImageResId() {
return navigationOptionImageResId;
}
public int getCode() {
return code;
}
public static RootNavigationOption fromCode(int code) {
switch(code) {
case 0:
return HOME;
case 1:
return SETTINGS;
case 2:
return LOGOUT;
default:
throw new RuntimeException(
"Illegal RootNavigationOption: " + code);
}
}
}
然后可以这样使用:
// Put
Bundle bundle = new Bundle();
bundle.putInt("key", RootNavigationOption.HOME.getCode());
// Get
RootNavigationOption rootNavigationOption = RootNavigationOption.fromCode(bundle.getInt("key"));