詳細介紹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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM