Android:将可序列化对象传递给Activity时出现ClassNotFoundException

15

我有几个来自 Android 市场的崩溃报告日志,类似于这样:

Exception class: java.lang.ClassNotFoundException

Source method: PathClassLoader.findClass()

java.lang.RuntimeException: Unable to start activity ComponentInfo{my.app.package/my.app.package.MyActivity}: java.lang.RuntimeException: Parcelable encounteredClassNotFoundException reading a Serializable object (name = my.app.package.a.ae)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2833)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2854)
at android.app.ActivityThread.access$2300(ActivityThread.java:136)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2179)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:5068)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: Parcelable encounteredClassNotFoundException reading a Serializable object (name = my.app.package.a.ae)
at android.os.Parcel.readSerializable(Parcel.java:1951)
at android.os.Parcel.readValue(Parcel.java:1822)
at android.os.Parcel.readMapInternal(Parcel.java:2008)
at android.os.Bundle.unparcel(Bundle.java:208)
at android.os.Bundle.getBundle(Bundle.java:1078)
at android.app.Activity.onRestoreInstanceState(Activity.java:861)
at android.app.Activity.performRestoreInstanceState(Activity.java:835)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1135)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2811)
... 11 more
Caused by: java.lang.ClassNotFoundException: my.app.package.a.ae
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:235)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2590)
at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1846)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:826)
at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2066)
at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:929)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2285)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2240)
at android.os.Parcel.readSerializable(Parcel.java:1945)
... 19 more
Caused by: java.lang.NoClassDefFoundError: my.app.package.a.ae
... 29 more
Caused by: java.lang.ClassNotFoundException: my.app.package.a.ae in loader dalvik.system.PathClassLoader[.]
at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:243)
at java.lang.ClassLoader.loadClass(ClassLoader.java:573)
at java.lang.ClassLoader.loadClass(ClassLoader.java:532)
... 29 more 
请注意我正在使用Proguard->这就是为什么“缺少”的类名是“a.ae”的原因。
实际上,“a.ae”是Proguard给类“MyObject”赋予的名称,如下所示。

你有任何想法为什么会发生这种情况吗?

我不认为这与Proguard有关,因为如果是由Proguard类重命名引起的问题,它应该一直发生,并且我应该能够自己复制此问题。

这是否与将可序列化对象传递给MyActivity有关?
在MyActivity中,我有

public void onCreate(Bundle savedInstanceState) {  
     myObj = (MyObject) getIntent().getSerializableExtra("nameOfMyObject");  
//here I am trying to read myObj's properties and app seems to crash here  

}


MyObject是一个拥有多种类成员的实体,例如:
public class MyObject implements Serializable {

    /** Generated serialVersionUID */
    static final long serialVersionUID = -267025879233327409L;

    static final String CONSTANT1 = "xpto";

    LinkedHashMap<String, Object> components;

    ArrayList<String> prop1;

    (...)
}

我正在使用以下代码启动MyActivity:

MyObject obj = new MyObj(stuff);
Intent intent;
intent = new Intent(CurrentActivity.this, MyActivity.class);
intent.putExtra("nameOfMyObject",  obj);
CurrentActivity.this.startActivity(intent);

你认为这与对象被传递的方式有关吗(作为可序列化的额外项)?如果我找不到其他解决方案,我想将对象自己“序列化”为字符串,然后传递字符串额外信息。您对此有什么看法?

编辑:我已尝试在模拟器和以下设备中重现此问题,但没有成功:

-Motorola Milestone 2 Android 2.2
-Samsung Galaxy Tab Android 2.2
-Vodafone 845 Android 2.1
-HTC Tatoo Android 1.6
-Xperia X10 Android 1.6
-Nexus One Android 2.2
-Google G1 Android 1.5

是否有任何新的想法?


你的对象是否可序列化? - Flo
我们需要一些代码来看看你想做什么... - Beasly
@Flo:是的,我的对象是可序列化的。 - pandre
@Beasly:public void onCreate(Bundle savedInstanceState) { myObj = (MyObject) getIntent().getSerializableExtra("nameOfMyObject"); //在这里我试图读取myObj的属性,但应用程序似乎在这里崩溃了 } - pandre
编写一个快速测试类,对您的对象进行序列化和反序列化,以确认链中没有更深层次的类引起问题。 - John J Smith
@John J Smith 我已经这样做了,并且已经通过“Serializable”对象数千次,但我无法重现这个问题:S 我猜这是一种罕见的情况,只会在某些设备/情况下发生。 - pandre
3个回答

42

最终得出结论:这个问题是由Proguard引起的,更具体地说,是因为我没有正确的Proguard配置。

原来Proguard正在改变我的Serializable类名,这使得Class.forName(className)失败了。

我不得不重新配置我的proguard.cfg文件,添加以下几行:

-keep class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

5
将近2年了,你救了我的一天,伙计。谢谢+1。我也欣赏你对于发布自己答案的态度。 - stinepike
1
官方ProGuard说明:http://proguard.sourceforge.net/manual/examples.html#serializable - shkschneider
如果Proguard没有启用,而且仍然出现此错误呢? - behelit
1
在一些禁用了_Proguard_的_Samsung_设备上,我也遇到了这个问题。 - tahsinRupam

4

这就是我在尝试了Proguard更改后最终解决类似崩溃问题的方式。 - swanson

1

LinkedHashMap没有实现Serializable接口,这可能导致错误。尝试实现一个小型测试来序列化这个类,或者尝试删除LinkedHashMap并查看错误是否仍然存在。


谢谢你的建议。我会尝试这个方法,但主要问题是我无法复现这个问题,所以我甚至不能确定任何解决方案是否有效地解决了这个问题 :( - pandre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接