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

Android序列化Serializable和Parcelable的理解和区别

2017-12-22 19:48 701 查看

一.基本概念

(一)序列化的基本概念

在Android开发过程中,因为无法将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。

序列化,表示将一个对象转换成可存储或可传输的状态。而序列化后的对象,可以在网络上进行传输,也可以存储到本地。

(二)怎么通过序列化传输对象

Android中Intent如果要传递类对象,可以通过两种方式实现。

1.方式一:Serializable,要传递的类实现Serializable接口传递对象

2.方式二 : Parcelable,要传递的类实现Parcelable接口传递对象。

Serializable(Java自带):

Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。

Parcelable(Android 专用):

除了Serializable之外,使用Parcelable也可以实现相同的效果,

不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。

二.基本使用

(一)Serializable, 简单易用

我们先看Serializable的代码。弄一个实体类 Person,利用Java自带的Serializable进行序列化

public class Person implements Serializable{

private static final long serialVersionUID = 7382351359868556980L;
private String name;
private int age;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


在数据传递界面:

Intent intent = new Intent(MainActivity.this, SerializableActivity.class);

Person person = new Person();
person.setName("如花");
person.setAge(18);
intent.putExtra("put_ser_test", person);
startActivity(intent);


在数据接收界面:

Intent intent = getIntent();
Person per = (Person)intent.getSerializableExtra("put_ser_test");

mTvDate.setText("名字:" + per.getName() + "\n"
+ "年龄:" + per.getAge());


Serializable 到此完成,没什么好解释的。Serializable的优点就是简单。

(二)Parcelable, 速度至上

Parcelable在数据传递的使用方面,和Serializable一模一样。在数据的接收方面,唯一的区别在于Serializable是intent.getSerializableExtra,而Parcelable是getIntent().getParcelableExtra。

它们在使用上最大的区别,是实体类:

先看代码:

public class Pen implements Parcelable{

private String color;
private int size;

// 系统自动添加,给createFromParcel里面用
protected Pen(Parcel in) {
color = in.readString();
size = in.readInt();
}

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

/**
*
* @param in
* @return
* createFromParcel()方法中我们要去读取刚才写出的name和age字段,
* 并创建一个Person对象进行返回,其中color和size都是调用Parcel的readXxx()方法读取到的,
* 注意这里读取的顺序一定要和刚才写出的顺序完全相同。
* 读取的工作我们利用一个构造函数帮我们完成了
*/

@Override
public Pen createFromParcel(Parcel in) {
return new Pen(in); // 在构造函数里面完成了 读取 的工作
}

//供反序列化本类数组时调用的
@Override
public Pen[] newArray(int size) {
return new Pen[size];
}
};

@Override
public int describeContents() {
return 0;  // 内容接口描述,默认返回0即可。
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(color);  // 写出 color
dest.writeInt(size);  // 写出 size
}

// ======分割线,写写get和set
//个人自己添加
public Pen() {
}

//个人自己添加
public Pen(String color, int size) {
this.color = color;
this.size = size;
}

public String getColor() {
return color;
}

public void setColor(String color) {
this.color = color;
}

public int getSize() {
return size;
}

public void setSize(int size) {
this.size = size;
}

}


当你实现Parcelable接口后,Android Studio(as)就会提示你重写describeContents方法和writeToParcel方法。在writeToParcel方法中,需要写出

dest.writeString(color);  // 写出 color
dest.writeInt(size);  // 写出 size


写完后,发现as依旧提示报错:



你根据提示操作后,选择Add Parcelable Implementation,发现as自动添加了以下代码:

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

/**
*
* @param in
* @return
* createFromParcel()方法中我们要去读取刚才写出的name和age字段,
* 并创建一个Person对象进行返回,其中color和size都是调用Parcel的readXxx()方法读取到的,
* 注意这里读取的顺序一定要和刚才写出的顺序完全相同。
* 读取的工作我们利用一个构造函数帮我们完成了
*/

@Override
public Pen createFromParcel(Parcel in) {
return new Pen(in); // 在构造函数里面完成了 读取 的工作
}

//供反序列化本类数组时调用的
@Override
public Pen[] newArray(int size) {
return new Pen[size];
}
};


也就是,随便一个类实现了Parcelable接口一开始就会变成这样子。Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。

使用Parcelable在代码上的确比Serializable要麻烦一些,但也没有想象中那么麻烦,因为系统已经帮我们做了很多事情。接下来,我们只需要写写我们自己需要的构造方法,写一下私有变量的get和set就行了。

整个实现Parcelable的实体类就完成了。其实,还有更简单的方法.就是使用as的android parcelable code generator插件,一键生成。如何生成的教程,网上有很多。比如这篇[点击跳转]。(http://blog.csdn.net/kroclin/article/details/40902721)

按照教程操作,生成的代码和上述手写的一模一样。如果您是第一次使用android parcelable code generator插件,我简单说一下生成步骤:

1.写出变量

private String color;
private int size;


2.点击鼠标右键:

选择Genetate,然后选择Parcelable就可。截图如下:





这里,我们将实现Parcelable接口的方法进行简单说明一下:

方法功能标识符
createFromParcel(Parcel source)从序列化后的对象中创建原始对象
newArray(int size)创建指定长度的原始对象数组
Pen(Parcel in)从序列化后的对象中创建原始对象
writeToParcel(Parcel out,int flags)将当前对象写入序列化结构中PARCALABLE_WRITE_RETURN_VALUE
describeContents返回当前对象的内容描述,几乎所有情况都返回0,仅在当前对象中存在文件描述符时返回1CONTENTS_FILE_DESCRIPTOR

三.原理与性能比较

Serializable的有点在于你只需要对某个类以及它的属性实现Serializable 接口即可。Serializable 接口是一种标识接口(marker interface),这意味着无需实现方法,Java便会对这个对象进行高效的序列化操作。而缺点是:这种方法是使用了反射,序列化的过程较慢。这种机制会在序列化的时候创建许多的临时对象,容易触发垃圾回收。

而Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。根据 google 工程师的说法,这些代码将会运行地特别快。原因之一就是我们已经清楚地知道了序列化的过程,而不需要使用反射来推断。同时为了更快地进行序列化,对象的代码也需要高度优化。

那到底Parcelable比Serializable快多少呢?我们来进行测试:

(一)测试方法

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

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

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

参与测试的对象就是上面代码中的Person和 Pen。

在多种Android软硬件环境上进行测试(LG Nexus 4 – Android 4.2.2、Samsung Nexus 10 – Android 4.2.2、HTC Desire Z – Android 2.3.3)

(二)测试结果

测试结果如下图:



由此可以得出: Parcelable 比 Serializable快了10多倍。有趣的是,即使在Nexus 10这样性能强悍的硬件上,一个相当简单的对象的序列化和反序列化的过程要花将近一毫秒。

四.总结

如果您想让您开发的程序运行更流程,您需要多花点时间来实现 Parcelable ,因为这将会为你对象的序列化过程快10多倍,而且占用较少的资源。加上现在已经有了插件,实现Parcelable接口的实体类代码也可以一键生成,Parcelable 的缺点就显得微不足道了。

区别SerializableParcelable
所属APIJAVA APIAndroid SDK API
原理序列化和反序列化过程需要大量的I/O操作序列化和反序列化过程不需要大量的I/O操作
开销开销大开销小
效率很高
使用场景序列化到本地或者通过网络传输内存序列化
源码:

点击下载源码

关于我:

1.一个热爱Android编程,也乐于分享、交友的菜鸟。

我的QQ:984992087 微信:gaolhjy

2.GitHub地址 点击跳转

您的start就是我分享的最大动力。

参考资料:

序列化Serializable和Parcelable的理解和区别

Android系统中Parcelable和Serializable的区别
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: