当我们需要使用Intent或Binder传递对象数据时,就需要用到Serializable和Parcelable。
1、Serializable
Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化的对象可以在网络上进行传输,也可以存储到本地。
1.1、Serializable简介
Serializable是java提供的一个序列化接口,是一个空接口,为对象提供标准的序列化和反序列化操作。使用起来非常简单,只需要让对象实现Serializable接口即可。
public class Persion implements Serializable{
private static final long serialVersionUID=1L;
public String name;
public String sex;
public int age;
public Persion(String name,String sex,int age){
this.name=name;
this.sex=sex;
this.age=age;
}
}
1.2、Serializable的序列化和反序列化
在上节中的Person类实现了Serializable接口,这样Person就变成了可序列化的了,我们就可以使用Intent进行数据的传递了。使用如下:
Person p=new Person("张三丰","男",100);
Intent intent=new Intent(this,TestActivity.class);
intent.putExtra("person_data",p);
startActivity(intent)
看下在TestActivity中进行数据的接收:
Person p=getIntent().getSerializableExtra("person_data");
这种传递对象的工作原理就是:先将一个对象序列化成可存储或可传输的状态,传递给下一个Activity,在下一个Activity需要将其反序列化成一个新的对象。注意这两个对象中的数据虽然完全相同,但并不是相同的对象。
下面再看下如何将对象序列化到本地,并从本地反序列化得到对象。具体代码如下:
//序列化对象到本地
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
Person p1 = new Person();
out.writeObject(p1);
out.close();
//反序列化对象
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
Person p2 = (Person) in.readObject();
in.close();
同样的序列化到本地的对象和反序列化得到的对象虽然数据相同,但是并不是一个对象。
1.3、serialVersionUID的作用
还记的上面我们在定义Person类时中定义了一个
private static final long serialVersionUID=1L;
那么这个serialVersionUID有什么作用呢?serialVersionUID主要用于反序列化,在反序列化时会检测文件中的serialVersionUID和当前类中的serialVersionUID是否一致,若不一致则会反序列化失败。所以一般我们应该指定serialVersionUID,否则当序列化的类中的变量的数量或类型发生变化时,系统默认生成的serialVersionUID就会发生变化,这就和之前序列化时的serialVersionUID不一致了,所以无法正常反序列化。
2、Parcelable
除了Serializable之外,我们还可以使用Parcelable来实现同样的效果。Parcelable是Android提供的,Parcelable的实现原理是将一个完整的对象进行拆解。而分解后的每一部分是可序列化的。而Serializable是将整个对象进行序列化。
下面看下Parcelable的使用
public class Person implements Parcelable {
private String name;
private int age;
protected Person(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(age);
}
}
可以看到我们重写了方法describeContents()
和writeToParcel()
,describeContents()
方法直接返回0即可,而在writeToParcel()
方法中我们需要调用parcel.writeXXX()
将Person中的字段一 一写出。
除此之外,我们还必须在Person类中提供一个名为CREATOR的匿名类实现。这里创建了Creator接口的实现,在其中重写了createFromParcel()
和newArray()
,在createFromParcel()
中需要创建一个Person对象返回,并读取刚才写出的name和age字段。其中name和age通过in.readXXX()
读取的,注意这里的读取顺序要和写入的顺序一致。而newArray()
只需要返回Person数组即可。
使用Intent传递对象的具体使用如下:
Person p=new Person("张三丰","男",100);
Intent intent=new Intent(this,TestActivity.class);
intent.putExtra("person_data",p);
startActivity(intent)
但是在TestActivity中获取数据的代码有所不同
Person p=(Person) intent.getParcelableExtra("person_data");
3、选择的原则
- 1、如果仅仅是在内存中使用,比如Activity、Service间进行对象的传递 ,推荐使用Parcelable,因为Parcelable的性能比Serializable高很多。因为Serializable在序列化时产生很多临时变量,从而引起频繁的GC。
- 2、如果是持久化操作,推荐使用Serializable,因为使用Parceable不能很好的保证数据的连续性。
4、本质的区别
- 1、Serializable的本质是使用了反射,序列化的过程比较慢,这种机制在序列化的时候会创建很多临时的对象,比引起频繁的GC、
- 2、Parcelable方式的本质是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的类型,这样就实现了传递对象的功能了。
网友评论