详细介绍Android中Parcelable的原理和使用方法

经常阅读博客是个好习惯
推荐技术小黑屋的Blog

引言

特别鸣谢:  Android中Parcel的解读 https://www.jianshu.com/p/32a2ec8f35ae

目录

  1. Parcelable的简单介绍
    1.1 Parcelable的简介
    1.2 Parcel的简介
    1.3 Parcelable中的三大过程介绍(序列化,反序列化,描述)
  2. Parcelable的使用和源码解读
  3. Parcelable中对象和集合的处理
  4. Parcelable和Serializable的区别和比较

1.1 Parcelable的简单介绍

介绍Parcelable不得不先提一下Serializable接口,Serializable是Java为我们提供的一个标准化的序列化接口,那什么是序列化呢? ---- 简单来说就是将对象转换为可以传输的二进制流(二进制序列)的过程,这样我们就可以通过序列化,转化为可以在网络传输或者保存到本地的流(序列),从而进行传输数据 ,那反序列化就是从二进制流(序列)转化为对象的过程.

Parcelable是Android为我们提供的序列化的接口,Parcelable相对于Serializable的使用相对复杂一些,但Parcelable的效率相对Serializable也高很多,这一直是Google工程师引以为傲的,有时间的可以看一下Parcelable和Serializable的效率对比 Parcelable vs Serializable 号称快10倍的效率

那我们看一下Android源码中的Parcelable

    /**
     * Interface for classes whose instances can be written to
   * and restored from a {@link Parcel}.  Classes implementing the Parcelable
 * interface must also have a non-null static field called <code>CREATOR</code>
 * of a type that implements the {@link Parcelable.Creator} interface.
 * 
 * <p>A typical implementation of Parcelable is:</p>
 * 
 * <pre>
 * public class MyParcelable implements Parcelable {
 *     private int mData;
 *
 *       public int describeContents() {
 *         return 0; * } * * public void writeToParcel(Parcel out, int flags) { * out.writeInt(mData); * } * * public static final Parcelable.Creator<MyParcelable> CREATOR * = new Parcelable.Creator<MyParcelable>() { * public MyParcelable createFromParcel(Parcel in) { * return new MyParcelable(in); * } * * public MyParcelable[] newArray(int size) { * return new MyParcelable[size]; * } * }; * * private MyParcelable(Parcel in) { * mData = in.readInt(); * } * }</pre> */ 

通过源码中的介绍 可以知道,Parcelable接口的实现类是可以通过Parcel写入和恢复数据的,并且必须要有一个非空的静态变量 CREATOR, 而且还给了一个例子,这样我们写起来就比较简单了,但是简单的使用并不是我们的最终目的

通过查看Android源码中Parcelable可以看出,Parcelable实现过程主要分为序列化,反序列化,描述三个过程,下面分别介绍下这三个过程

1.2 Parcel的简介

在介绍之前我们需要先了解Parcel是什么?Parcel翻译过来是打包的意思,其实就是包装了我们需要传输的数据,然后在Binder中传输,也就是用于跨进程传输数据

简单来说,Parcel提供了一套机制,可以将序列化之后的数据写入到一个共享内存中,其他进程通过Parcel可以从这块共享内存中读出字节流,并反序列化成对象,下图是这个过程的模型。

 
Parcel模型

Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。

Parcelable通过Parcel实现了read和write的方法,从而实现序列化和反序列化,我们在源码中看一下

 
Parcel中的Read方法
 
Parcel中的write方法

可以看出包含了各种各样的read和write方法,最终都是通过native方法实现

 
Parcel中的native方法

1.3 Parcelable中的三大过程介绍(序列化,反序列化,描述)

到这里,基本上关系都理清了,也明白简单的介绍和原理了,接下来在实现Parcelable之前,介绍下实现Parcelable的三大流程
首先写一个类实现Parcelable接口,会让我们实现两个方法

 
要实现的方法
1.3.1 描述

其中describeContents就是负责文件描述,首先看一下源码的解读

 
描述的源码

通过上面的描述可以看出,只针对一些特殊的需要描述信息的对象,需要返回1,其他情况返回0就可以

1.3.2 序列化

我们通过writeToParcel方法实现序列化,writeToParcel返回了Parcel,所以我们可以直接调用Parcel中的write方法,基本的write方法都有,对象和集合比较特殊下面单独讲,基本的数据类型除了boolean其他都有,Boolean可以使用int或byte存储

举个例子:我们将上面的User对象实现序列化,User对象包含三个字段 age,name,isMale

 /**
 * 该方法负责序列化
 * @param dest
 * @param flags
 */
@Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(age); dest.writeString(name); // boolean 可以使用int或byte方式进行存储,怎么存就怎么取 dest.writeInt(isMale ? 1 : 0); } 
1.3.3 反序列化

反序列化需要定义一个CREATOR的变量,上面也说了具体的做法,这里可以直接复制Android给的例子中的,也可以自己定义一个(名字千万不能改),通过匿名内部类实现Parcelable中的Creator的接口

/**
 * 负责反序列化
 */
public static final Creator<User> CREATOR = new Creator<User>() { /** * 从序列化后的对象中创建原始对象 */ @Override public User createFromParcel(Parcel source) { return new User(source); } /** * 创建指定长度的原始对象数组 */ @Override public User[] newArray(int size) { return new User[size]; } }; public User(Parcel parcel) { age = parcel.readInt(); name = parcel.readString(); isMale = parcel.readInt() == 1; } 

2. Parcelable的实现和使用

根据上面三个过程的介绍,Parcelable就写完了,就可以直接在Intent中传输了,可以自己写两个Activity传输一下数据试一下,其中一个putExtra另一个getParcelableExtra即可

这里实现Parcelable也很简单

1.写一个类实现Parcelable然后alt+enter 添加Parcelable所需的代码块,AndroidStudio会自动帮我们实现(这里需要注意如果其中包含对象或集合需要把对象也实现Parcelable)

 
Paste_Image.png

3. Parcelable中对象和集合的处理

如果实现Parcelable接口的对象中包含对象或者集合,那么其中的对象也要实现Parcelable接口


public class ReportDetial implements Parcelable{

    public ArrayList<ReportEntityFather> details; //报告明细
public String requestName; //报告名称
public String reportNo; //报告单号
public String cardNo; //病人卡号
public String name; //病人姓名


public static final Creator<ReportDetial> CREATOR = new Creator<ReportDetial>() {
@Override
public ReportDetial createFromParcel(Parcel in) {
entity.reportNo = in.readString();
entity.requestName = in.readString();
entity.cardNo = in.readString();
entity.name = in.readString();
entity.details = in.createTypedArrayList(ReportEntityFather.CREATOR);
return entity;
}

@Override
public ReportDetial[] newArray(int size) {
return new ReportDetial[size];
}
};

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(reportNo);
dest.writeString(requestName);
dest.writeString(cardNo);
dest.writeString(name);
dest.writeTypedList(details);
}
}

这里包含一个ReportEntityFather对象和ReportEntityFather集合

首先ReportEntityFather需要先实现Parcelable:

public class ReportEntityFather implements Parcelable{
public String reportNo; //报告单号
public String deptName; //检查科室
public String result; //结果
public String resultReference; //结果值参考
public String highOrLow; //高低标志
public String remarks ; //备注
public String checkTime ; //送检时间

//反序列化
    public static final Creator<ReportEntityFather> CREATOR = new Creator<ReportEntityFather>() {
@Override
public ReportEntityFather createFromParcel(Parcel in) {
ReportEntityFather entity=new ReportEntityFather();
entity.reportNo = in.readString();
entity.deptName = in.readString();
entity.result = in.readString();
entity.resultReference = in.readString();
entity.highOrLow = in.readString();
entity.remarks = in.readString();
entity.checkTime = in.readString();
return entity;
}

@Override
public ReportEntityFather[] newArray(int size) {
return new ReportEntityFather[size];
}
};

@Override
public int describeContents() {
return 0;
}

序列化:
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(reportNo);
dest.writeString(deptName);
dest.writeString(result);
dest.writeString(resultReference);
dest.writeString(highOrLow);
dest.writeString(remarks);
dest.writeString(checkTime);
}

写入和读取集合有两种方式,
一种是写入类的相关信息,然后通过类加载器去读取, --> writeList | readList
二是不用类相关信息,创建时传入相关类的CREATOR来创建 --> writeTypeList | readTypeList | createTypedArrayList
第二种效率高一些

一定要注意如果有集合定义的时候一定要初始化 like this -->
public ArrayList<Author> authors = new ArrayList<>();

4. Parcelable和Serializable的区别和比较

Parcelable和Serializable都是实现序列化并且都可以用于Intent间传递数据,Serializable是Java的实现方式,可能会频繁的IO操作,所以消耗比较大,但是实现方式简单 Parcelable是Android提供的方式,效率比较高,但是实现起来复杂一些 , 二者的选取规则是:内存序列化上选择Parcelable, 存储到设备或者网络传输上选择Serializable(当然Parcelable也可以但是稍显复杂)

文章转载自:https://www.jianshu.com/p/32a2ec8f35ae

转载于:https://www.cnblogs.com/tingtasia/p/11288574.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值