您的位置:首页 > 移动开发 > Android开发

Android开发艺术探索<Android的序列化>

2016-12-14 02:11 465 查看


1.定义:

       序列化是将对象转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到存储区域。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

序列化: 将数据结构或对象转换成二进制串的过程

反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程


2.性能:

  第一、空间, 序列化需要在原有的数据上加上描述字段,以为反序列化解析之用。如果序列化过程引入的额外开销过高,可能会导致过大的网络,磁盘等各方面的压力。对于海量分布式存储系统,数据量往往以TB为单位,巨大的的额外空间开销意味着高昂的成本。

  第二、时间,复杂的序列化协议会导致较长的解析时间,这可能会使得序列化和反序列化阶段成为整个系统的瓶颈。


3.Serializable和Parcelable的比较

    Android中实现序列化有两种选择,分别来介绍。

    3.1-Serializable

        Java提供的一个空接口,只需要实现Serializable接口即可,然后声明一个serialVersionUID=873568055688767即可实现序列化,以下示例:

       (1)User是一个实现了serializable接口的类。

public class User implements Serializable {

private static final long serialVersionUID = -257491624569718892L;

private int userId;

private String userName;

private boolean isMale;


public User(int userId, String userName, boolean isMale) {

this.userId = userId;

this.userName = userName;

this.isMale = isMale;

}

}


       (2)序列化过程,通过ObjectOutputStram即可实现。

String path = Environment.getExternalStorageDirectory() + File.separator + "cache.txt";

File file = new File(path);

if (!file.exists()) {

file.mkdirs();

}

User user = new User(1, "lisi", false);

try {

ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(path));

stream.writeObject(user);

stream.close();

} catch (IOException e) {

e.printStackTrace();

}


    (3)反序列化过程    

User o = null;

try {

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(path));

o = (User) inputStream.readObject();

} catch (Exception e) {

e.printStackTrace();

}


    反序列化过程通过ObjectInputStream可以实现,恢复的User对象数据一样,但是两者不是同一个对象。

    注意:

  serialVersionUID用来辅助实现序列化和反序列化,在序列化的过程中系统会把UID写入到序列化的文件中,在反序列化的时候去检测文件中的UID,当两者一致的时候说明两个类的版本是一致的,可以成功反序列化,否则反序列化失败,当然不用声明也可以,系统会默认提供,但是编译器实现的会有区别也可能导致意外的java.io.InvalidClassException.

  静态成员变量属于类,不属于对象,不参与序列化过程。

  transient关键字声明的变量不参与序列化过程。


   3.2-Parcelable

    序列化过程是由writeToParcel方法完成,通过Parcel的一系列write方法实现,

    反系列化是通过CREATOR实现,内部类,标明如何去创建序列化对象和数组,最终通过Parcel的一系列read方法实现。

    再往底层走,首先是将Parcel(Java)对象转换成Parcel(C++)对象,然后被封装在Parcel中的相关数据由C++底层来完成数据的序列化操作.整个读写全是在内存中进行,主要是通过malloc()、realloc()、memcpy()等内存操作进行,所以效率比JAVA序列化中使用外部存储器会高很多,就是使用麻烦。

    序列化示例:

public class Book implements Parcelable {


private String name;

private String author;

private int price;

   //
private Customer user;
 

public Book(String name, String author, int price) {

this.name = name;

this.author = author;

this.price = price;

}


//从序列化的对象中创建原始对象

protected Book(Parcel in) {

name = in.readString();

author = in.readString();

price = in.readInt();

       //
user = in.readParcelable(Thread.currentThread().getContextClassLoader()); 
}

public static final Creator<Book> CREATOR = new Creator<Book>() {

@Override

//从序列化的对象中创建原始对象

public Book createFromParcel(Parcel in) {

return new Book(in);

}


@Override

//创建指定长度的原始对象数组

public Book[] newArray(int size) {

return new Book[size];

}

};


@Override

//返回当前对象的内容描述,如果含有文件描述符,返回1

public int describeContents() {

return 0;

}


@Override

//将当前对象写入序列化结构,flags为1表示当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0

public void writeToParcel(Parcel dest, int flags) {

dest.writeString(name);

dest.writeString(author);

dest.writeInt(price);

       //dest.writeParcelable(user,0);   

}

}


然后就可以通过Intent传输了,像Intent,Bundle等类都实现了Parcelable接口。
 注意:

    如果内部有另一个可序列化对象,在反序列化过程中要传递当前线程的上下文类加载器,否则序列化失败。


异同:

Serializable使用了反射,会产生很多临时变量,导致频繁GC;Parcelable是以Ibinder作为信息载体的,在内存中完成序列化,速度快效率高。
在读写数据的时候,Parcelable是在内存中直接进行读写,因此在内存之间进行数据传递的时候,Android推荐使用Parcelable;而Serializable是通过使用IO流的形式将数据读写入在硬盘上,文件存储的时候推荐使用Serializable;


4.总结

     Java应用程序中有Serializable来实现序列化操作,Android中有Parcelable来实现序列化操作,虽然Parcelable的性能要强于Serializable,但是仍然有特殊的情况需要使用Serializable,而不去使用Parcelable,因为Parcelable无法将数据进行持久化,因此在将数据保存在磁盘的时候,仍然需要使用后者,因为前者无法很好的将数据进行持久化.

参考链接:http://kb.cnblogs.com/page/515982/

                  http://greenrobot.me/devpost/android-parcelable-serializable/
      
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: