6.3 序列化相关的异常
Android中的序列化分两种,一种是原始的Serializable,另一种是Android为了提升性能而量身打造的Parcelable。接下来将介绍序列化不当导致的异常。
6.3.1 实体对象不支持序列化
异常中的关键字:
Parcelable encountered IOException writing serializable object(name=xxx)……
发生频率:★★★
看下面这个实体类,它看上去是支持序列化的:
public class UserInfo implements Serializable { private static final long serialVersionUID = 1L; private String username; private CreditCard creditCard; public UserInfo(){ }
看其中的CreditCard实体,它的定义如下:
public class CreditCard { public String cardNO;
也就是说,CreditCard类不支持序列化。那么,当UserInfo对象中CreditCard属性的值为空时,没有任何问题;而一旦CreditCard属性值不为空,那么UserInfo在序列化的时候,就会因为这个属性不能序列化而崩溃。
提示 JSONObject和JSONArray不支持序列化
对于JSONObject和JSONArray这样的类型,也是不支持序列化的,所以实体中一旦有这样的属性,必然崩溃。
6.3.2 序列化时未指定ClassLoader
异常中的关键字:
BadParcelableException:ClassNotFoundException when unmarshalling……
发生频率:★★
在使用Parcelable机制的时候,会遇到上述异常信息。
比如说下面这个序列号类MyParcelable,有个自定义类型ClassA的属性a:
public class MyParcelable implements Parcelable { private String mStr; private ClassA a; … .. // 省略若干语句 private MyParcelable(Parcel in) { mStr = in.readString(); a = in.readParcelable(null); } }
崩溃出在最后一句上,对a的反序列化上:
a = in.readParcelable(null);
当把它改为下面这样,就不会再崩溃了:
a=in.readParcelable(ClassA.class.getClassLoader());
提示 ClassLoader的概念
当ClassLoader为空时,系统会采取默认的ClassLoader。
Android有两种不同的ClassLoader:framework ClassLoader和apk ClassLoader,其中framework ClassLoader知道怎么加载Android系统内部的类;apk ClassLoader知道怎么加载我们自己写的类,也知道怎么加载Android系统内部的类。
在App刚启动时,默认ClassLoader是apk ClassLoader,但在系统内存不足应用被系统回收会再次启动,这个默认ClassLoader会变为framework ClassLoader,所以对于我们自己的类会报ClassNotFoundException。
6.3.3 反序列化时发现类找不到:被ProGuard混淆导致的崩溃
异常中的关键字:
Parcelable encountered ClassNotFoundException reading a Serializable object……
发生频率:★★
在反序列化的时候,发现有个类找不到。一般而言,这样的崩溃,在开发调试期间就会暴露出来。但为什么开发期间没事发到线上就出问题了呢?StackOverfiow上有个哥们契而不舍的花了2年时间查这个问题,最后发现是ProGuard导致的。
ProGuard对于Class.forName(className)中的class是无能为力的,它会将这个class混淆得面目全非,于是在反序列化这个类的时候却发现找不到这个类了,自然就会抛出这种异常信息了。相应的解决方案就是,在ProGuard文件中keep这个类。 [1]
6.3.4 反序列化时发现类找不到:传入畸形数据
异常中的关键字:
Parcelable encountered ClassNotFoundException reading a Serializable object(name=某个类名称)
发生频率:★★
这是一个最近发现的安全漏洞。
由于在App中使用了getSerializableExtra()的API,App开发人员没有对传入的数据做异常判断,别有企图的人可以通过传入畸形数据,导致本地拒绝服务。
例如传入简单类型,比如Integer,就会抛出类型转换异常ClassCastException。
而当传入自定义的可序列化对象时,就会抛出上述带有ClassNotFoundException的异常信息了。 [2]
6.3.5 反序列化时出错
异常中的关键字:
Could not read input channel file descriptors from parcel……
发生频率:★★★
出现这个异常,一般是因为Intent传递的数据太大了,貌似大于1MB就会崩溃。
此外,网上也有人说是因为FileDescripter太多而且没有关闭,或looper太多没有退出导致的,我没有验证过,仅供参考。
[1] 详细信息请参见http://stackoverf iow.com/questions/6014806/android-classnotfoundexception-when-passing-serializable-object-to-activity。
[2] 这个安全漏洞由360近期发现,参见http://blogs.360.cn/360mobile/2015/01/06/android-app通用型拒绝服务漏洞分析报告/。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论