序列化的目的
将对象数据转换成字节流形式
我们知道网络传输是以字节流的方式对数据进行传输的。而当我们通过Intent和Binder传输数据时,无论何种类型的数据,都以字节流形式传送。
对象的序列化主要用途:
- 永久的保存对象(将对象保存在文件或者磁盘中)
- 方便对象数据在网络与进程间进行传递
Android中实现序列化的方式
-
实现Serializable接口
import java.io.Serializable;
使用方法只需要实现Serializable即可
import java.io.Serializable;
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/11
* @Description:
*/
public class Person implements Serializable{
private static final long serialVersionUID = 4890701529857339249L;
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;
}
}
设置Android studio实现Serializable自动生成serialVersionUID步骤:
1、File–>Settings–>Editor–>Inspections–>Java–>Serialization issues–>Serializable class without ‘serialVersionUID’ 勾选中该选项即可。
2、进入实现了Serializable中的类,选中类名,Alt+Enter弹出提示,然后直接导入完成
serialVersionUID的作用:
serialVersionUID: 字面意思上是序列化的版本号,是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量;原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常地被反序列化。(当serialVersionUID一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化;否则说明当前类和反序列化的类相比发生了某些变化,比如成员变量的数量、类型发生了变化,这个时候是无法正常反序列化的)
为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。当然也可以不那么做!
对于使用序列化的两点注意:
对于使用序列化还有两点需要注意:
1.静态成员变量属于类不属于对象,所以不参与序列化过程
2.用transient关键字标记的成员变量不参与序列化过程
上述两点注意同样适用Parcelable
-
实现Parcelable接口
import android.os.Parcelable;
Parcelable相比Serializable具有更好的性能,但是使用更复杂,Parcelable不仅仅需要声明,还需要实现内部的相应方法,不过这些AS可以帮我们做好。
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/11
* @Description:
*/
public class Person implements Parcelable{
private String name;
private int age;
private List<String> child;
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;
}
public List<String> getChild() {
return child;
}
public void setChild(List<String> child) {
this.child = child;
}
protected Person(Parcel in) {
name = in.readString();
age = in.readInt();
child = in.createStringArrayList();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
/**
* 从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层
* 简单来说就是将Parcel对象映射成你的对象
* @param in
* @return
*/
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
/**
* 内容接口描述,默认返回0就可以
* @return
*/
@Override
public int describeContents() {
return 0;
}
/**
* 将对象序列化为一个Parcel对象
* @param dest
* @param flags
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
dest.writeStringList(child);
}
}
Kotlin实现方式:
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/11
* @Description:
*/
data class Person(val name:String,val age:Int,val child:List<String>):Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt(),
parcel.createStringArrayList()) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeInt(age)
parcel.writeStringList(child)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Person1> {
override fun createFromParcel(parcel: Parcel): Person1 {
return Person1(parcel)
}
override fun newArray(size: Int): Array<Person1?> {
return arrayOfNulls(size)
}
}
}
注意:写入数据的顺序和读出数据的顺序必须是相同的.
比较
-
Serializable在序列化操作的时候会产生大量的临时变量,(原因是使用了反射机制)从而导致GC的频繁调用,因此在性能上会稍微逊色
-
Parcelable是以Ibinder作为信息载体的.在内存上的开销比较小,因此在内存之间进行数据传递的时候,Android推荐使用Parcelable,既然是内存方面比价有优势,那么自然就要优先选择。
-
在读写数据的时候,Parcelable是在内存中直接进行读写,而Serializable是通过使用IO流的形式将数据读写入在硬盘上。Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性。
网友评论