一、简介

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操作