Android对象序列化两种方式详解(Parcelable和Serializable)

在讲解对象序列化之前首先了解一下UUID类,UUID类是一种生成无重复字符串的一种程序类,这种程序类的主要功能是根据时间戳实现一个自动的无重复的字符串定义(这里所说的无重复并不是说不会出现重复,只是说重复的概率很低,大概是千万亿分之一)。在生成UUID的时候一般不会使用它的构造方法,一般使用的是这个方法:public static UUID randomUUID()

当然也可以根据字符串获取UUID内容:public static UUID fromString(String name);

UUID一般用在对一些文件进行自动命名处理,因为你要是不用UUID,那么就要自己计算。一般网上的图片命名都是使用的这种命名,所以下载的网上的图片都是很长一串这种类型的字符。

以上UUID跟下面序列化讲解没关系,只是我突然想到的知识点,记下来的。

 

对象序列化是指:将内存中保存的是对象以二进制数据流的形式进行处理,可以实现对象的保存或者是网络传输。这句话的意思可以这么理解:

java中的每一个对象都是存放在堆内存中,也就是用户电脑的堆内存中,现在用户觉得堆内存中的对象很重要,需要另外保存,可能需要把该对象保存到文件中,也可能通过网络上传到服务器,也可能是保存到数据库中等等(如下图)。但是不管怎么说,堆内存中的对象如果要实现上面的保存等操作,需要先把该对象转换成二进制数据流,对象序列化就是把对象向二进制数据流转换的核心操作。

Android对象序列化两种方式详解(Parcelable和Serializable)_第1张图片

总结起来,在Android端对象序列化的目的有以下几点:

  (1)永久的保存对象数据(将对象数据保存在文件当中,或者是磁盘中

  (2)通过序列化操作将对象数据在网络上进行传输(由于网络传输是以字节流的方式对数据进行传输的.因此序列化的目的是将对象数据转换成字节流的形式)

  (3)将对象数据在进程之间进行传递(Activity之间传递对象数据时,需要在当前的Activity中对对象数据进行序列化操作.在另一个Activity中需要进行反序列化操作讲数据取出)

  (4)Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长(即每个对象都在JVM中)但在现实应用中,就可能要停止JVM运行,但有要保存某些指定的对象,并在将来重新读取被保存的对象。这是Java对象序列化就能够实现该功能。(可选择入数据库、或文件的形式保存)

  (5)序列化对象的时候只是针对变量进行序列化,不针对方法进行序列化.

  (6)在Intent之间,基本的数据类型直接进行相关传递即可,但是一旦数据类型比较复杂的时候,就需要进行序列化操作了.

 

然而并不是所有的类都能够实现对象序列化,要想实现对象序列化,那么该类必须要实现java.io.Serializable父接口,作为序列化的标记,通过查看文档可以知道这个接口并没有多余的方法,因为它描述的是一种类的能力。(在java中有两个)


class Person implements Serializable{
	//为了在不同的虚拟机上不产生反序列化问题,一般会警告添加一个版本
	//编号,这里选择压制,也就是不写
	//private static final long serialVersionUID = 1L;
	private String name;
	private int age;
	public Person(String name,int age) {
		this.name=name;
		this.age=age;
	}
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}

此时的Person类就是一个可以被序列化的类,Person类的每一个对象都可以实现二进制的数据传输,属于可以被序列化的程序类。

有了序列化的支持类之后,如果要想实现序列化与反序列化操作,则可以利用下面两个类的操作:(首先记住对象序列化和反序列化只有字节型,没有字符型)

Android对象序列化两种方式详解(Parcelable和Serializable)_第2张图片Android对象序列化两种方式详解(Parcelable和Serializable)_第3张图片

有了上面的方法支持,下面来看对象序列化和反序列化的实现:

Android对象序列化两种方式详解(Parcelable和Serializable)_第4张图片

需要注意的是:在java中的对象序列化和反序列化必须使用内部提供的对象操作流,因为这里面牵涉到二进制数据的格式,所以不能够自定义处理,如果要想实现一组对象的序列化,则可以使用对象数组完成。

我们知道在Java应用程序当中对类进行序列化操作只需要实现Serializable接口就可以,由系统来完成序列化和反序列化操作,但是在Android中序列化操作有另外一种方式来完成,那就是实现Parcelable接口.也是Android中特有的接口来实现类的序列化操作.原因是Parcelable的性能要强于Serializable.因此在绝大多数的情况下,Android还是推荐使用Parcelable来完成对类的序列化操作的.

 

Android中如何使用Parcelable进行序列化操作

说了这么多,我们还是来看看Android中如何去使用Parcelable实现类的序列化操作吧.
 Implements Parcelable的时候需要实现内部的方法:

1).writeToParcel 将对象数据序列化成一个Parcel对象(序列化之后成为Parcel对象.以便Parcel容器取出数据)

2).重写describeContents方法,默认值为0

3).Public static final Parcelable.CreatorCREATOR (将Parcel容器中的数据转换成对象数据) 同时需要实现两个方法:
  3.1 CreateFromParcel(从Parcel容器中取出数据并进行转换.) 
  3.2 newArray(int size)返回对象数据的大小

 因此,很明显实现Parcelable并不容易。实现Parcelable接口需要写大量的模板代码,这使得对象代码变得难以阅读和维护。具体的实例就是上面Parcelable的实例代码.就不进行列举了.(有兴趣的可以去看看Android中NetWorkInfo的源代码,是关于网络连接额外信息的一个相关类,内部就实现了序列化操作.大家可以去看看)

Parcelable序列化方式:(不仅仅需要声明,还需要实现内部的相应方法)
 

public class Book implements Parcelable{
 private String bookName;
 private String author;
 private int publishDate;
  
 public Book(){
   
 }
  
 public String getBookName(){
  return bookName;
 }
  
 public void setBookName(String bookName){
  this.bookName = bookName;
 }
  
 public String getAuthor(){
  return author;
 }
  
 public void setAuthor(String author){
  this.author = author;
 }
  
 public int getPublishDate(){
  return publishDate;
 }
  
 public void setPublishDate(int publishDate){
  this.publishDate = publishDate;
 }
  
 @Override
 public int describeContents(){
  return 0;
 }
  
 @Override
 public void writeToParcel(Parcel out, int flags){
  out.writeString(bookName);
  out.writeString(author);
  out.writeInt(publishDate);
 }
  
 public static final Parcelable.Creator CREATOR = new Creator(){
   
     @Override
  public Book[] newArray(int size){
   return new Book[size];
  }
   
  @Override
  public Book createFromParcel(Parcel in){
   return new Book(in);
  }
 };
  
 public Book(Parcel in){
  //如果元素数据是list类型的时候需要: lits = new ArrayList in.readList(list); 
  //否则会出现空指针异常.并且读出和写入的数据类型必须相同.如果不想对部分关键字进行序列化,可以使用transient关键字来修饰以及static修饰.
  bookName = in.readString();
  author = in.readString();
  publishDate = in.readInt();
 }
}

下面是MainActivity中的代码:

Book book = new Book();
book.setBookname("Darker");
book.setBookauthor("me");
book.setPublishDate(20);
Bundle bundle = new Bundle();
bundle.putParcelable("book", book);
Intent intent = new Intent(MainActivity.this,AnotherActivity.class);
intent.putExtras(bundle);

下面是AnotherActivity中的代码:

Intent intent = getIntent();
Bundle bun = intent.getExtras();
Book book = bun.getParcelable("book");
System.out.println(book);

Parcelable和Serializable比较:

首先Parcelable的性能要强于Serializable的原因我需要简单的阐述一下

  1). 在内存的使用中,前者在性能方面要强于后者

  2). 后者在序列化操作的时候会产生大量的临时变量,(原因是使用了反射机制)从而导致GC的频繁调用,因此在性能上会稍微逊色

  3). Parcelable是以Ibinder作为信息载体的.在内存上的开销比较小,因此在内存之间进行数据传递的时候,Android推荐使用Parcelable,既然是内存方面比价有优势,那么自然就要优先选择.

  4). 在读写数据的时候,Parcelable是在内存中直接进行读写,而Serializable是通过使用IO流的形式将数据读写入在硬盘上.

  但是:虽然Parcelable的性能要强于Serializable,但是仍然有特殊的情况需要使用Serializable,而不去使用Parcelable,因为Parcelable无法将数据进行持久化,因此在将数据保存在磁盘的时候,仍然需要使用后者,因为前者无法很好的将数据进行持久化.(原因是在不同的Android版本当中,Parcelable可能会不同,因此数据的持久化方面仍然是使用Serializable)

 

 

 

你可能感兴趣的:(Android,java)