序列化:在數(shù)據(jù)傳輸中,如果要傳輸?shù)氖菍?duì)象,這時(shí)候就用到我們的序列化和反序列化。有時(shí)候想將對(duì)象持久化儲(chǔ)存在設(shè)備或者網(wǎng)絡(luò)上,這時(shí)建議使用 Serializable
- Serializable : java 提供的接口 ,使用簡(jiǎn)單,直接實(shí)現(xiàn)這個(gè)接口就行。下面是一個(gè)使用栗子。
public class User implements Serializable {
private static final long serialVersionUID = 1L; // 防止java.io.InvalidClassException
//private String testError;
private int userId;
private String userName;
public User(int userId, String userName) {
this.userId = userId;
this.userName = userName;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
值得注意的是: private static final long serialVersionUID = 1L;
建議我們使用 Serializable 接口的時(shí)候都手動(dòng)去指定,雖然是非必須的,但是:如果不指定 serialVersionUID ,User 類(lèi)序列化后,如果中途增加或減少一個(gè)成員變量(比如新增 private String testError; ),這時(shí)我們?nèi)シ葱蛄谢瘜?bào)錯(cuò):java.io.InvalidClassException
為什么?序列化的時(shí)候系統(tǒng)把當(dāng)前類(lèi)的serialVersionUID 寫(xiě)入系列化文件中,當(dāng)反序列化的時(shí)候會(huì)去檢測(cè)文件中的serialVersionUID ,如果一致說(shuō)明兩者版本相同,否則說(shuō)明兩者相比發(fā)生了某些變化 ,這時(shí)就報(bào)錯(cuò)。
/**
* 序列化保存 Serializable 數(shù)據(jù)
*
* @param user
*/
private void saveAsSerializable(User user) {
Log.d("saveAsSerializable", "User:" + user.getUserName() + " " + user.getUserId());
FileOutputStream fos;
ObjectOutputStream oos;
try {
fos = getApplicationContext().openFileOutput("cache1.txt",
Context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(user);
oos.close();
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 反序列化讀取 Serializable 數(shù)據(jù)
*
* @return
*/
private User readSerializable() {
User obj = null;
FileInputStream fis;
ObjectInputStream ois;
try {
fis = getApplicationContext().openFileInput("cache1.txt");
ois = new ObjectInputStream(fis);
obj = (User) ois.readObject();
ois.close();
fis.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (obj != null) {
Log.d("readSerializable", "User:" + obj.getUserName() + " " + obj.getUserId());
return obj;
} else {
return null;
}
}
- Parcelable:
Android 專(zhuān)用的一個(gè)接口,經(jīng)別人測(cè)試,性能比 Serializable 好10倍左右,當(dāng)在對(duì)象持久化儲(chǔ)存時(shí)不建議使用這個(gè)。
下面是個(gè)栗子,其實(shí)編譯器已經(jīng)幫忙生成了大部分代碼,我們只要寫(xiě)get 、set 和構(gòu)造函數(shù)就行:
public class Human implements Parcelable {
private String address;
private boolean isMan;
private Woman woman;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public boolean isMan() {
return isMan;
}
public void setMan(boolean man) {
isMan = man;
}
public Woman getWoman() {
return woman;
}
public void setWoman(Woman woman) {
this.woman = woman;
}
public Human(String address, boolean isMan, Woman woman) {
this.address = address;
this.isMan = isMan;
this.woman = woman;
}
protected Human(Parcel in) {
address = in.readString();
isMan = in.readInt() == 1;
//反序列化 Woman 屬性,由于 Woman 是另一個(gè)可序列化對(duì)象,所以它的反序列化過(guò)程需要傳遞當(dāng)前線程的上下文類(lèi)加載器,否則會(huì)報(bào)無(wú)法找到該類(lèi)的錯(cuò)誤。
woman = in.readParcelable(Woman.class.getClassLoader());
}
public static final Creator<Human> CREATOR = new Creator<Human>() {
@Override
public Human createFromParcel(Parcel in) {
return new Human(in);
}
@Override
public Human[] newArray(int size) {
return new Human[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(address);
parcel.writeInt(isMan ? 1 : 0);
parcel.writeParcelable(woman, i);
}
}
這里敲一下黑板:
需要注意的是 Parcelable 不支持布爾值傳輸,怎樣使用請(qǐng)看上面栗子;
當(dāng)我們序列化的類(lèi)中有其他對(duì)象,如例子上的 Woman 類(lèi) ,那么這個(gè)類(lèi)也必須實(shí)現(xiàn) Parcelable 接口,同時(shí):反序列化 Woman 屬性,由于 Woman 是另一個(gè)可序列化對(duì)象,所以它的反序列化過(guò)程需要傳遞當(dāng)前線程的上下文類(lèi)加載器,否則會(huì)報(bào)無(wú)法找到該類(lèi)的錯(cuò)誤(實(shí)現(xiàn)Parcelable 接口生成代碼的時(shí)候已經(jīng)自動(dòng)寫(xiě)了)。(這里得說(shuō)一下:生成代碼前先把所有的成員變量都寫(xiě)了,方便自動(dòng)生成,不然中途調(diào)加變量要相應(yīng)的補(bǔ)上序列化和反序列化的實(shí)現(xiàn))
下面是 Parcelable 的序列化與反序列化持久化存儲(chǔ)的代碼,建議 Intent 傳輸用 Parcelable 。
/**
* 序列化保存 Parcalable 數(shù)據(jù)
*
* @return
*/
private void saveParce(Human human) {
Log.d("loadParce", "Human:" + human.getAddress() + " " + human.getWoman().getName());
FileOutputStream fos;
try {
fos = getApplicationContext().openFileOutput("cache2.txt",
Context.MODE_PRIVATE);
BufferedOutputStream bos = new BufferedOutputStream(fos);
Parcel parcel = Parcel.obtain();
parcel.writeParcelable(human, 0);
bos.write(parcel.marshall());
bos.flush();
bos.close();
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 反序列化讀取 Parcalable 數(shù)據(jù)
*
* @return
*/
private void loadParce() {
FileInputStream fis;
try {
fis = getApplicationContext().openFileInput("cache2.txt");
byte[] bytes = new byte[fis.available()];
fis.read(bytes);
Parcel parcel = Parcel.obtain();
parcel.unmarshall(bytes, 0, bytes.length);
parcel.setDataPosition(0);
Human data = parcel.readParcelable(Human.class.getClassLoader());
Log.d("loadParce", "Human:" + data.getAddress() + " " + data.getWoman().getName()+"isMan: "+ data.isMan());
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
用 Intent 傳輸就賊簡(jiǎn)單了, putExtra 傳過(guò)去后,采用Serializable 接口的用 getIntent().getSerializableExtra ()、采用 Parcelable 接口的用getIntent().getParcelableExtra() 取出來(lái)就行。下面是網(wǎng)上看到的別人使用的代碼(采用 Parcelable 接口):
MainActivity 中
Intent mTvOpenThird = new
Intent(MainActivity.this,ThirdActivity.class);
Pen tranPen = new Pen();
tranPen.setColor("big red");
tranPen.setSize(98);
// public Intent putExtra(String name, Parcelable value)
mTvOpenThird.putExtra("parcel_test",tranPen);
startActivity(mTvOpenThird);
ThirdActivity 中
Pen pen = (Pen)getIntent().getParcelableExtra("parcel_test");
mTvThirdDate = (TextView) findViewById(R.id.mTvThirdDate);
mTvThirdDate.setText("顏色:"+pen.getColor()+"\\n"
+"大小:"+pen.getSize());
- 小結(jié)一下:Serializable 使用簡(jiǎn)單但開(kāi)銷(xiāo)較大,序列化和反序列化過(guò)程需要大量I/O操作,建議都指定
serialVersionUID,隨便什么數(shù)值。所以如果考慮效率的話首選 Parcelable,Parcelable 主要用在內(nèi)存序列化上,如果將對(duì)象持久化保存建議使用 Serializable 。Demo