最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android序列化之Parcelable和Serializable的使用詳解

 更新時(shí)間:2018年01月02日 10:51:28   作者:Jdqm  
本篇文章主要介紹了Android序列化之Parcelable和Serializable的使用詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

序列化與反序列

首先來(lái)了解一下序列化與反序列化。

序列化

由于存在于內(nèi)存中的對(duì)象都是暫時(shí)的,無(wú)法長(zhǎng)期駐存,為了把對(duì)象的狀態(tài)保持下來(lái),這時(shí)需要把對(duì)象寫(xiě)入到磁盤或者其他介質(zhì)中,這個(gè)過(guò)程就叫做序列化。

反序列化

反序列化恰恰是序列化的反向操作,也就是說(shuō),把已存在在磁盤或者其他介質(zhì)中的對(duì)象,反序列化(讀取)到內(nèi)存中,以便后續(xù)操作,而這個(gè)過(guò)程就叫做反序列化。

概括性來(lái)說(shuō)序列化是指將對(duì)象實(shí)例的狀態(tài)存儲(chǔ)到存儲(chǔ)媒體(磁盤或者其他介質(zhì))的過(guò)程。在此過(guò)程中,先將對(duì)象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉(zhuǎn)換為字節(jié)流,然后再把字節(jié)流寫(xiě)入數(shù)據(jù)流。在隨后對(duì)對(duì)象進(jìn)行反序列化時(shí),將創(chuàng)建出與原對(duì)象完全相同的副本。

實(shí)現(xiàn)序列化的必要條件

一個(gè)對(duì)象要實(shí)現(xiàn)序列化操作,該類就必須實(shí)現(xiàn)了Serializable接口或者Parcelable接口,其中Serializable接口是在java中的序列化抽象類,而Parcelable接口則是android中特有的序列化接口,在某些情況下,Parcelable接口實(shí)現(xiàn)的序列化更為高效,關(guān)于它們的實(shí)現(xiàn)案例我們后續(xù)會(huì)分析,這里只要清楚知道實(shí)現(xiàn)序列化操作時(shí)必須實(shí)現(xiàn)Serializable接口或者Parcelable接口之一即可。

序列化的應(yīng)用情景

主要有以下情況(但不限于以下情況)

1)內(nèi)存中的對(duì)象寫(xiě)入到硬盤;
2)用套接字在網(wǎng)絡(luò)上傳送對(duì)象;
3)通過(guò)RMI(Remote Method Invoke 遠(yuǎn)程方法調(diào)用)傳輸對(duì)象;

1.Parcelable和Serializable有什么用,它們有什么差別?

Parcelable和Serializable是兩個(gè)接口,它們的作用是讓實(shí)現(xiàn)了其中一個(gè)接口的類的對(duì)象能夠被序列化和反序列化。

(1)Serializable是java提供的序列化接口,它是一個(gè)空的接口,僅標(biāo)識(shí)該類型可序列化的,具體的序列化/反序列化工作由 ObjectInputStream(readObject)/ObjectOutputStream(writeObject) 完成,這個(gè)過(guò)程包含大量的I/O操作,使用比較簡(jiǎn)單,但需要考量性能的影響。使用場(chǎng)景:將對(duì)象持久化到存儲(chǔ)介質(zhì)或者通過(guò)網(wǎng)絡(luò)傳輸。

(2)Parcelable接口是Android平臺(tái)下的序列化接口,通??邕M(jìn)程傳遞的數(shù)據(jù)都要正確實(shí)現(xiàn)這個(gè)接口,比如Intent,Bitmap等。Parcelable實(shí)現(xiàn)起來(lái)比Serializable復(fù)雜,但性能較好。使用場(chǎng)景:在內(nèi)存中實(shí)現(xiàn)序列化,例如跨進(jìn)程傳遞。若某個(gè)字段不需要序列化,在實(shí)現(xiàn) writeToParcel 方法中忽略此字段即可。

2.自定義一個(gè)類讓其實(shí)現(xiàn)Parcelable,大致流程是什么?

(1)首先實(shí)現(xiàn)Parcelable接口,并實(shí)現(xiàn)接口中的方法。

/**
 * 返回當(dāng)前對(duì)象的內(nèi)容描述,如果有文件描述符返回1,否則返回0。
 */
@Override
public int describeContents() {
 return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
 dest.writeInt(userId);
 dest.writeString(userName);
 dest.writeInt(isMan ? 1 : 0);
}

(2)接著創(chuàng)建一個(gè)Parcelable接口內(nèi)部的接口類型Creator的一個(gè)成員,內(nèi)部需要用到一個(gè)帶一個(gè)Parcel參數(shù)的構(gòu)造方法。

protected User(Parcel in) {
 userId = in.readInt();
 userName = in.readString();
 isMan = in.readByte() != 0;
}

/**
 * 在aidl中,參數(shù)使用in或者inout來(lái)修飾時(shí),服務(wù)端的onTransact()會(huì)調(diào)用CREATOR中方法來(lái)反序列化客戶端傳過(guò)來(lái)的參數(shù)
 */
public static final Creator<User> CREATOR = new Creator<User>() {
 @Override
 public User createFromParcel(Parcel in) {
  return new User(in);
 }

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

(3)如果在aidl文件中使用out或者inout定向tag來(lái)修飾參數(shù),還必須實(shí)現(xiàn)一個(gè) readFromParcel(Parcel) 方法,這是因?yàn)槭褂眠@兩個(gè)定向tag修飾的參數(shù),在服務(wù)端onTransact()返回后,客戶端會(huì)調(diào)用 readFromParcel() 來(lái)讀?。ǚ葱蛄谢reply中的數(shù)據(jù)。該方法與writeToParcel是對(duì)應(yīng)的,實(shí)現(xiàn)如下:

public void readFromParcel(Parcel in) {
 userId = in.readInt();
 userName = in.readString();
 isMan = in.readInt() == 1 ? true : false;
}

3.實(shí)現(xiàn)Serializable接口

通過(guò)實(shí)現(xiàn)Serializable接口來(lái)實(shí)現(xiàn)序列化比較簡(jiǎn)單,只需要實(shí)現(xiàn)該接口,并指定 serialVersionUID 即可,當(dāng)然這個(gè)ID是可選的,可以不手動(dòng)指定。通過(guò)ObjectIntputStream /ObjectOutputStream來(lái)序列化和反序列化。

ObjectOutputStream oos = null;
try {
 oos = new ObjectOutputStream(new FileOutputStream(new File("sdcard/user.cache")));
 User user = new User(111, "Jdqm", true);
 oos.writeObject(user);
} catch (IOException e) {
 e.printStackTrace();
} finally {
 try {
  oos.close();
 } catch (IOException e) {
  e.printStackTrace();
 }
}
ObjectInputStream ois = null;
try {
 ois = new ObjectInputStream(new FileInputStream(new File("sdcard/user.cache")));
 User user = (User) ois.readObject();
 Log.d(TAG, "user: " + user);
} catch (IOException | ClassNotFoundException e) {
 e.printStackTrace();
} finally {
 try {
  ois.close();
 } catch (IOException e) {
  e.printStackTrace();
 }
}

輸出結(jié)果

User{userId=111, userName='Jdqm', isMan=true}

serialVersionUID的意義:輔助完成序列化和反序列化,當(dāng)一個(gè)類實(shí)現(xiàn)SerSerializable接口,沒(méi)有添加serialVersionUID的作用字段時(shí),IDE會(huì)發(fā)出警告,這個(gè)字段可以手動(dòng)指定一個(gè)值,比如1L,也可指定為IED根據(jù)類的結(jié)構(gòu)生成一個(gè)long值,它們的效果是一樣的。在序列化時(shí)會(huì)將這個(gè)值寫(xiě)入存儲(chǔ)介質(zhì),反序列化時(shí)就校驗(yàn)本地類的serialVersionUID和序列化介質(zhì)中的是否一致,不一致將拋出異常 java.io.InvalidClassException

(1)若不指定:系統(tǒng)會(huì)根據(jù)類的結(jié)構(gòu)計(jì)算出一個(gè)serialVersionUID,一旦類的結(jié)構(gòu)發(fā)生改變這個(gè)值就會(huì)改變,將導(dǎo)致反序列化失??;

(2)指定一個(gè)值:當(dāng)類的結(jié)構(gòu)發(fā)生改變時(shí),也可以不修改serialVersionUID的值,這種情況下能最大程度上通過(guò)反序列化回復(fù)數(shù)據(jù),若類的結(jié)構(gòu)發(fā)生毀滅性的改變,例如字段數(shù)據(jù)類型改變了,也會(huì)導(dǎo)致反序列失敗。

Note: 類的結(jié)構(gòu)發(fā)生改變指的是類的成員變量的改變,添加一個(gè)普通的方法是不會(huì)導(dǎo)致計(jì)算得到的serialVersionUID改變的。構(gòu)造方法、toString()、getter/setter改變會(huì)引起serialVersionUID改變。

  1. transient修飾的成員變量不參與序列化,反序列化時(shí)改成員為該數(shù)據(jù)類型的默認(rèn)值
  2. 靜態(tài)成員不參與序列化
  3. 反序列化得到的一個(gè)新對(duì)象的過(guò)程并沒(méi)有調(diào)用構(gòu)造方法

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

广丰县| 洛阳市| 清新县| 家居| 察雅县| 乐陵市| 湘西| 清新县| 呼和浩特市| 天柱县| 抚州市| 锦州市| 崇州市| 敖汉旗| 黄梅县| 黑河市| 韶山市| 松江区| 洪湖市| 正宁县| 永春县| 策勒县| 绥滨县| 丹江口市| 青海省| 凯里市| 贵南县| 绥滨县| 嘉荫县| 博爱县| 新乡县| 绵竹市| 若尔盖县| 奎屯市| 互助| 东乌珠穆沁旗| 巴南区| 新和县| 贵港市| 大荔县| 元阳县|