一、简介
Serializable 和 Parcelable 是Android两种序列化方式,Serializable是java的方式,Pacelable是Android独有的方式
二、使用
1、Serializable
(1)实现Serializable 接口
(2)重写 serialVersionUID变量,serialVersionUID如果不手动设置,系统会生成一个serialVersionUID。但如果是系统生成的有可能会发生改变,比如类的属性或者方法,如果发生了变化,会抛出InvalidClassException。所以最后好手动设置
(3)持久化使用
序列化输出 ,ObjectOutputStream
ObjectOutputStream(FileOutputStream(path))
.apply {
writeObject(People("lilei", 27))
flush()
close()
}
反序列化,ObjectInputStream
ObjectInputStream(FileInputStream(path))
.apply {
text.text = readObject().toString()
close()
}
(4)非持久化,例如 Intent方式传递
public @NonNull Intent putExtra(String name, @Nullable Serializable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putSerializable(name, value);
return this;
}
2、 Parcelable
package com.androidtv.pos.model.request;
import android.os.Parcel;
import android.os.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>()
{
/**
* 创建指定长度的原始对象数组
* @param size
* @return
*/
@Override
public Book[] newArray(int size)
{
return new Book[size];
}
/**
* 从序列化对象中,获取原始的对象
* @param in
* @return
*/
@Override
public Book createFromParcel(Parcel in)
{
return new Book(in);
}
};
/**
* 序列化
*
* @param in
*/
public Book(Parcel in)
{
bookName = in.readString();
author = in.readString();
publishDate = in.readInt();
}
}
有对象或者集合操作
package com.androidtv.pos.model.request;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
/**
* Created by wuqiqi on 2020/10/13.
*/
public class ParcelDemo implements Parcelable {
private int count;
private String name;
private ArrayList<String> tags;
private Book book;
// ***** 注意: 这里如果是集合 ,一定要初始化 *****
private ArrayList<Book> books = new ArrayList<>();
/**
* 序列化
*
* @param in
*/
protected ParcelDemo(Parcel in) {
count = in.readInt();
name = in.readString();
tags = in.createStringArrayList();
// 读取对象需要提供一个类加载器去读取,因为写入的时候写入了类的相关信息
book = in.readParcelable(Book.class.getClassLoader());
//读取集合也分为两类,对应写入的两类
//这一类需要用相应的类加载器去获取
in.readList(books, Book.class.getClassLoader());// 对应writeList
//这一类需要使用类的CREATOR去获取
in.readTypedList(books, Book.CREATOR); //对应writeTypeList
//books = in.createTypedArrayList(Book.CREATOR); //对应writeTypeList
//这里获取类加载器主要有几种方式
getClass().getClassLoader();
Thread.currentThread().getContextClassLoader();
Book.class.getClassLoader();
}
public static final Creator<ParcelDemo> CREATOR = new Creator<ParcelDemo>() {
@Override
public ParcelDemo createFromParcel(Parcel in) {
return new ParcelDemo(in);
}
@Override
public ParcelDemo[] newArray(int size) {
return new ParcelDemo[size];
}
};
/**
* 描述
*
* @return
*/
@Override
public int describeContents() {
return 0;
}
/**
* 反序列化
*
* @param dest
* @param flags
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(count);
dest.writeString(name);
//序列化一个String的集合
dest.writeStringList(tags);
// 序列化对象的时候传入要序列化的对象和一个flag,
// 这里的flag几乎都是0,除非标识当前对象需要作为返回值返回,不能立即释放资源
dest.writeParcelable(book, 0);
// 序列化一个对象的集合有两种方式,以下两种方式都可以
//这些方法们把类的信息和数据都写入Parcel,以使将来能使用合适的类装载器重新构造类的实例.所以效率不高
dest.writeList(books);
//这些方法不会写入类的信息,取而代之的是:读取时必须能知道数据属于哪个类并传入正确的Parcelable.Creator来创建对象
// 而不是直接构造新对象。(更加高效的读写单个Parcelable对象的方法是:
// 直接调用Parcelable.writeToParcel()和Parcelable.Creator.createFromParcel())
dest.writeTypedList(books);
}
}
三、源码简单解析
Serializable的源码如下
* @author unascribed
* @see java.io.ObjectOutputStream
* @see java.io.ObjectInputStream
* @see java.io.ObjectOutput
* @see java.io.ObjectInput
* @see java.io.Externalizable
* @since JDK1.1
*/
public interface Serializable {
}
要注意Serializable在Intent中传递也用到了Parcel这个类
方法如下
public final void writeSerializable(@Nullable Serializable s) {
if (s == null) {
writeString(null);
return;
}
String name = s.getClass().getName();
writeString(name);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(s);
oos.close();
writeByteArray(baos.toByteArray());
} catch (IOException ioe) {
throw new RuntimeException("Parcelable encountered " +
"IOException writing serializable object (name = " + name +
")", ioe);
}
}
Bundle中也实现了Parcelable接口
public final class Bundle extends BaseBundle implements Cloneable, Parcelable
ObjectOutputStream 对象操作流继承了 OutputStream,字节流
public class ObjectOutputStream
extends OutputStream implements ObjectOutput, ObjectStreamConstants
四、对比
1、Parcelable相对于Serializable的使用相对复杂一些。
2、Parcelable的效率相对Serializable也高很多。
3、Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable在外界有变化的情况下不能很好的保证数据的持续性。尽管Serializable效率低点,但此时还是建议使用Serializable。存储到设备或者网络传输上选择Serializable。
4、Pacelable使用原理是内存共享,是通过Parcel容器做的处理,Parcel:有一个专门负责IBinder传输数据的容器。
(一个可以进程共享的内存区)Parcel可以把数据压入,另一端的Parcel可以把数据取走(通过实现我们可以推断出保存数据的是一个先进先出的堆栈)Parcel仅仅是为了实现高性能的IPC通信,在其他的持久化方案在并不推荐。
5、Serializable是使用ObjectOutputStream 和 ObjectInputStream 字节流,把对象转成字节流,但转成字节流过程中会生成大量临时变量,效率较低,持久化使用了I/O操作