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

Android序列化——Serializable与Parcelable

2016-01-03 21:33 621 查看
序列化这个名词,我们在学习java的时候早有耳闻,与之相对的还有反序列化。

在java中我们印象中常用的序列化方式是实现Serializable接口。

那么,在android中,我们如何实现这样的序列化和反序列化呢?

序列化的意义

序列化,我们首先要明白它代表的含义以及为什么要使用序列化。
序列化:将对象转为字节序列的过程,我们称之为序列化。
序列化的意义:序列化主要是为了解决对象的持久化以及对象在进程间的传递、网络传输等。
(1)持久化:当你在一个程序中,声明一个类的后,程序关闭,那么这个类也肯定是被内存释放了。如果你想要在程序关闭后,这个类内容仍然能存在,那么你就需要对它做持久化操作。常用的方法是:用对象处理流(ObjectOutputStream)来把这个类对象存储在本地(这个过程,就是序列化-持久化过程)。当你想使用这个已经被序列化-持久化的类对象时,用对象处理流(ObjectInputStream)取得类对象数据,加载到程序中。
(2)进程间对象传递:比如,两个操作系统之间的两个进程A与B,因为不公用内存。你如果想要从A传递一个类对象到B,那么,你需要把A的类对象字节化,在B中接收字节并处理。字节是两个系统都认可并能处理的方式。

序列化的方式

Android中序列化有哪些方式?
以下两种,就是Android中涉及到的序列化接口。
(1)Serializable
如果你想要使用这个序列化方式。那你首先要实现这个接口,这个Serializable接口只是一个标志,并不需要实现它的类做额外的操作。
当实现这个接口后,Android(java)系统会自动完成这个接口的序列化。
(2)Parcelable
如果你想要使用这个序列化方式。那你首先也是实现这个接口。与Serializable相比,这个接口,需要你实现几个必要的接口方法。并在方法中写入代码。

序列化的使用——数据传输

对于上面我们介绍的两种序列化方式,我们分别也做演示,看看在Android中如何使用。

Serializable的使用

它的使用,在android中是很简单的:实现序列化接口,传递实现序列化接口的类对象,解析传递过来的序列化类对象。
具体的代码:
(1)序列化接口实现
package com.example.serializ_csdn;

import java.io.Serializable;

public class SerializableClass implements Serializable{

/**
* UID,默认有两种方式。如果不限制使用,可直接使用以下1L方式
* 如果对序列化验证严格,可用另一种方式,生成一长串long数据。
*/
private static final long serialVersionUID = 1L;
/**
* 以下是类的元素
*/
private String name;
private int age;
private boolean isMan;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
/**
* @return the isMan
*/
public boolean isMan() {
return isMan;
}
/**
* @param isMan the isMan to set
*/
public void setMan(boolean isMan) {
this.isMan = isMan;
}

}
这个类定义的很简单。类中的属性元素有三项,名字、年龄、是否男。
(2)序列化接口实现类的传递
我们在android中加入如下代码,用于界面的跳转(从mainactivity.java跳转到otheractivity.java):
SerializableClass sClass=new SerializableClass();
sClass.setName("赵云");
sClass.setAge(18);
sClass.setMan(true);

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

intent.putExtra("tag", 1);
intent.putExtra("s_data", sClass);
startActivity(intent);
这里我们看到,类对象做了组装,并且用“s_data”作为标识,传递这个类对象到OtherActivity中。
(3)序列化接口实现类的接收和解析
现在让我们看看,在OtherActivity.java中,我们是如何接收并解析的。
SerializableClass sClass=(SerializableClass)this.getIntent().getSerializableExtra("s_data");
上面这句代码,就完成了它的序列化解析。它包含了反序列化的过程。

从上面的写法,我们看出,这是一种很简便的写法。那么Parcelable的接口实现是怎么样的呢?

Parcelable的使用

Parcelable的接口实现,我们也用代码来说明。我们用同样的类属性:名字、年龄、是否男。
(1)Parcelable接口的实现
package com.example.serializ_csdn;

import android.os.Parcel;
import android.os.Parcelable;

public class ParcelableClass implements Parcelable{

private String name;
private int age;
private boolean isMan;

/**
* @return the name
*/
public String getName() {
return name;
}

/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}

/**
* @return the age
*/
public int getAge() {
return age;
}

/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}

/**
* @return the isMan
*/
public boolean isMan() {
return isMan;
}

/**
* @param isMan the isMan to set
*/
public void setMan(boolean isMan) {
this.isMan = isMan;
}

@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeString(name);
dest.writeInt(age);
dest.writeInt(isMan?1:0);
}

public final static  Parcelable.Creator<ParcelableClass> CREATOR =new Parcelable.Creator<ParcelableClass>() {

@Override
public ParcelableClass createFromParcel(Parcel source) {
// TODO Auto-generated method stub
ParcelableClass pClass=new ParcelableClass();
pClass.name=source.readString();
pClass.age=source.readInt();
pClass.isMan=(source.readInt()==1)?true:false;
return pClass;
}

@Override
public ParcelableClass[] newArray(int size) {
// TODO Auto-generated method stub
return new ParcelableClass[size];
}
};

}


你会发现,Parcelable的写法比起Serializable的写法复杂了。它要实现两个必要的方法和一个接口。
必要实现方法:writeToParcel、describeContents。分别代表写入数据到Parcel以及内容描述。writeToParcel我们可以理解为流写入Parcel、describeContents方法一般默认返回0即可。
必要实现接口:public final static  Parcelable.Creator<ParcelableClass> CREATOR。这是个很特别的接口,按约定,这个接口的名字你还不能更改,只能是CREATOR,并且前面的修饰需要时public final static。
CREATOR接口的实现中,有两个方法,createFromParcel(可以看成是从Parcel中获取流,与上方的writeToParcel相对应),newArray(返回多个类对象)。

(2)Parcelable接口实现类的传递
ParcelableClass pClass=new ParcelableClass();
pClass.setName("关羽");
pClass.setAge(20);
pClass.setMan(true);

Intent intent2=new Intent();
intent2.setClass(this, OtherActivity.class);
intent2.putExtra("tag", 2);
intent2.putExtra("p_data", pClass);
startActivity(intent2);


(3)Parcelable接口实现类的接收与解析

ParcelableClass pClass=(ParcelableClass)this.getIntent().getParcelableExtra("p_data");


对比,这两个接口实现类的使用。你轻易发现,Serializable的使用更方便,Parcelable的使用比较麻烦。那我们如何选择使用哪个序列化方法呢?

序列化的使用——持久化

上面我们讲的主要是序列化接口在数据传递过程中的使用,那么在序列化的持久化,我们怎么用代表描述呢?
一般情况下,持久化我们选择使用Serializable接口。这里有一个序列化和反序列化过程。
序列化:
以下就是一个持久化过程,将类对象持久化到obj中。
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("obj"));
out.writeObject(new SerializableClass());
out.flush();
out.close();


反序列化:
以下就是一个从obj中读取类对象数据的过程,就是反序列化。
ObjectInputStream in=new ObjectInputStream(new FileInputStream("obj"));
in.readObject();
in.close();


序列化接口的选择

Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据,而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化。

以上主要是对序列化的一些简要归纳。

源码

演示源码地址:Android序列化——Serializable与Parcelable
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息