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

Android进阶二:序列化总结(基础篇)

2017-09-18 22:06 246 查看

一、Java对象与Java对象序列化的区别

  Java对象存在的前提必须在JVM运行期间存在,如果想在JVM非运行的情况下或者在其他机器JVM上获取指定Java对象,在现有Java对象的机制下都不可能完成。

  与Java对象不同的是,如果对Java对象执行序列化操作,因为原理是把Java对象信息保存到存储媒介,所以可以在以上Java对象不可能存在的情况下依然可以使用Java对象。

二、序列化的目的

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

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

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

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

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

三、Android中实现序列化的两种方式

Serializable用于对对象进行本地存储和网络传输比较多

Parcalable由于内存开销小,所以在内存间数据传输时推荐使用Parcelable,用于进程间数据传递、组件间数据传递比较多,因为android不同版本Parcelable可能不同,所以不推荐Parcelable进行数据持久化

(1).Implements Serializable 接口 (声明一下即可)

Serializable 的简单实例:

public class Person implements Serializable{
private static final long serialVersionUID = -7060210544600464481L;
private String name;
private int age;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
}


(2).Implements Parcelable 接口(不仅仅需要声明,还需要实现内部的相应方法)

实现方法:

1、实现Parcelable接口

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

3、重写describeContents方法,默认值为0

4、Public static final Parcelable.CreatorCREATOR (将Parcel容器中的数据转换成对象数据) 同时需要实现两个方法:

  4.1 CreateFromParcel(从Parcel容器中取出数据并进行转换.)

  4.2 newArray(int size)返回对象数据的大小

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<Book> CREATOR = new Creator<Book>(){

     @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();
}
}


四、Parcelable与Serializable的各种使用

(1).Serializable进行保存对象到文件:

public static void seriaWrite(String path, Object object)
{
ObjectOutputStream objectOutputStream = null;
File file = new File(path);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if(file.exists()) {
file.delete();
}
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
objectOutputStream.writeObject(object);
} catch (IOException e) {
e.printStackTrace();
}
}


(2).Serializable读取文件中保存的对象:

public static Object seriaRead(String path)
{
File file = new File(path);
if(!file.exists())
return null;
ObjectInputStream objectInputStream = null;
try {
objectInputStream = new ObjectInputStream(new FileInputStream(file));
try {
return objectInputStream.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}


五、Parcelable与Serializable的性能比较

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

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

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

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

4. 速度:在读写数据的时候,Parcelable是在内存中直接进行读写,而Serializable是通过使用IO流的形式将数据读写入在硬盘上,很明显内存的读写速度通常大于IO读写

5.存储性:不同的Android版本当中,Parcelable可能会不同,因此数据的持久化方面仍然是使用Serializable)、

现在来针对存储速度做一个实验:

1)、通过将一个对象放到一个bundle里面然后调用Bundle.writeToParcel(Parcel, int)方法来模拟传递对象给一个activity的过程,然后再把这个对象取出来。

2)、在一个循环里面运行1000 次。

3)、两种方法分别运行10次来减少内存整理,cpu被其他应用占用等情况的干扰。

4)、参与测试的对象就是上面的相关代码

5)、在多种Android软硬件环境上进行测试

•LG Nexus 4 – Android 4.2.2

•Samsung Nexus 10 – Android 4.2.2

•HTC Desire Z –

Android 2.3.3

结果如图:



性能差异:

Nexus 10

Serializable: 1.0004ms, Parcelable: 0.0850ms – 提升10.16倍。

Nexus 4

Serializable: 1.8539ms – Parcelable: 0.1824ms – 提升11.80倍。

Desire Z

Serializable: 5.1224ms – Parcelable: 0.2938ms – 提升17.36倍。

由此可以得出: Parcelable 比 Serializable快了10多倍。

从相对的比较我们可以看出,Parcelable的性能要比Serializable要优秀的多,因此在Android中进行序列化操作的时候,我们需要尽可能的选择前者,但是需要花上大量的时间去实现Parcelable接口中的内部方法.

六、使用注意点

1.需要序列化的对象,对象内的其他实例化的对象也要能序列化

如:

public class ChuteBean implements Serializable{

private ArrayList<ClassBean> group1ClassBeenList;
}


如果ClassBean不能序列化,那ChuteBean的对象进行序列化再反序列化的时候就会出错。

2.序列化ID问题

序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。这也可能是造成序列化和反序列化失败的原因,因为不同的序列化id之间不能进行序列化和反序列化。

3.当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口

4.static,transient后的变量不能被序列化
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android