Android开发之漫漫长途 X——Android序列化

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!另外,本系列文章知识可能需要有一定Android开发基础和项目经验的同学才能更好理解,也就是说该系列文章面向的是Android中高级开发工程师。

前言

上一篇中我们比较详尽的分析了ServiceManager。那么本篇我们来讲一下Android序列化的相关知识。为什么跨度那么大,因为“任性”?其实不是的,同志们还记得上两篇出现的Parcel吗,Parcel是一个容器,他可以包含数据或者是对象引用,并且能够用于Binder的传输。同时支持序列化以及跨进程之后进行反序列化,同时其提供了很多方法帮助开发者完成这些功能。从上面的描述可以看出Parcel是进程间通信的数据载体。我们常常需要持久化一些对象,除了数据库等持久化方案之外,把对象转换成字节数组并通过流的方式存储在本地也是一个不错的方法,另外当我们需要通过Intent和Binder传输数据是就需要使用序列化后的数据。

Java中的Serializable

Serializable 是Java所提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作。使用Serializable来实现序列化相当简单,只需要在需要序列化的类实现Serializable接口并在其中声明一个类似下面的标识即可自动实现默认的序列化过程。

public class Person extends PersonParent implements Serializable { private static final long serialVersionUID = 1L; //静态域 public static int static_field; //transient域 public transient int transient_field; //一个普通的域 public String desc; public Person(String desc) { this.desc = desc; } static class PersonSerializableProxy implements Serializable{ private String desc; private PersonSerializableProxy(Person s) { this.desc = s.desc; } /** * 与writeReplace相同,ObjectInputStream会通过反射调用 readResolve()这个方法, * 决定是否替换反序列化出来的对象。 * @return */ private Object readResolve() { return new Person(desc); } } /** * * 在序列化一个对象时,ObjectOutputStream会通过反射首先调用writeReplace这个方法, * 在这里我们可以替换真正送去序列的对象, * 如果我们没有重写,那序列化的对象就是最开始的对象。 * @return */ private Object writeReplace() { //序列化Person的时候我们并没有直接写入Person对象,而是写入了PersonSerializableProxy对象 return new PersonSerializableProxy(this); } /** * 这里主要是为了防止攻击,任何以Person声明的对象字节流都是流氓!! * 因为我在writeReplace中已经把序列化的实例指向了SerializableProxy * @param stream * @throws InvalidObjectException */ private void readObject(ObjectInputStream stream) throws InvalidObjectException { throw new InvalidObjectException("proxy requied!"); } public static void main(String[] args) throws IOException, ClassNotFoundException { Person person = new Person("desc"); person.transient_field = 100; person.static_field = 10086; ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("cache.txt")); outputStream.writeObject(person); outputStream.flush(); outputStream.close(); person.static_field = 10087; ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cache.txt")); Person deserialObj = (Person) objectInputStream.readObject(); System.out.println(deserialObj); } } class PersonParent{ private String name; //PersonParent类要么继承自Serializable,要么需要提供一个无参构造器。 public PersonParent() { } public PersonParent(String name) { this.name = name; } }

不过在使用中也需要注意以下几个问题:

serialVersionUID用来标识当前序列化对象的类版本,建议每一个实现Serialization的类都指定该域。当然如果我们没有指定,JVM会根据类的信息自动生成一个UID。

被transient描述的域和类的静态变量是不会被序列化的,序列化是针对类实例。

需要进行序列化的对象所有的域都必须实现Serializable接口,不然会直接报错NotSerializableException。当然,有两个例外:域为空 或者域被transient描述是不会报错的。

如果一个实现了Serializable类的对象继承自另外一个类,那么这个类要么需要继承自Serializable,要么需要提供一个无参构造器。

反序列化产生的对象并不是通过构造器创建的,那么很多依赖于构造器保证的约束条件在对象反序列化时都无法保证。比如一个设计成单例的类如果能够被序列化就可以分分钟克隆出多个实例...

Android中的Parcelable

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwgsp.html