Android IPC機制(一):序列化與反序列化

mgjx5038 8年前發布 | 13K 次閱讀 ipc Android開發 移動開發 Android

一、前言

        對于Android開發者來說,IPC機制肯定不陌生,而作為Android的進階也必須掌握IPC機制。所謂IPC機制,即進程間通訊(Inter-Process Communication)。我們的應用有時候出于業務需要,可能是多進程的,而由于不同進程是不共享一個內存池的,所以進程之間不能直接通訊,而要通過一些特別的機制才能通訊,所以IPC機制是解決進程間通訊的一個方案。為了熟練掌握Android的IPC機制,我們先從基本的序列化與反序列化說起。

二、序列化與反序列化

        由于在系統底層,數據的傳輸形式是簡單的字節序列形式傳遞,即在底層,系統不認識對象,只認識字節序列,而為了達到進程通訊的目的,需要先將數據序列化,而序列化就是將對象轉化字節序列的過程。相反地,當字節序列被運到相應的進程的時候,進程為了識別這些數據,就要將其反序列化,即把字節序列轉化為對象。有了以上理解,接下來我們認識兩個用于序列化和反序列化的接口:Serializable接口和Parcelable接口。

三、Serializable接口

        Java提供了一個序列化接口,serialable接口,該接口在文檔中定義如下:Marks classes that can be serialized by ObjectOutputStream and deserialized by ObjectInputStream.從這句話可看出,該接口只是標記了當前類是可以序列化的,是一個空接口,僅僅提供了標志功能,具體的序列化與反序列化操作是由ObjectOutputStream和ObjectInputStream完成的。
        繼續讀文檔,發現該接口要求我們在實現了該接口的類中聲明如下的一個變量:

private static final long serialVersionUID= 1L;

        這個變量有什么用呢?試想一下,如果沒有手動指定該值,一開始序列化了classA,得到文件A,接著對classA的內部結構更改,比如添加了一個新的變量,那么此時反序列化則會失敗,因為實際上系統在序列化的時候,會自動計算出一個serialVersionUID值,并保存在已經序列化好的數據中,此時修改了classA,那么反序列化的時候系統就會重新計算一個新的serialVersionUID值,那么兩個值就會不相等,就會反序列化失敗。所以,手動指定一個值,能很大程度上保存數據,防止數據丟失。
        接下來,我們來看一下序列化和反序列化的具體步驟
        ·對象的序列化:
        (1)實例化一個對象輸出流:ObjectOutputStream,該對象輸出流可以包裝一個輸出流,比如文件輸出流。
        (2)使用ObjectOutputStream.writeObject(obj)進行寫對象。
        ·對象的反序列化:
        (1)實例化一個對象輸入流:ObjectInputStream,該對象輸入流可以包裝一個輸入流,比如文件輸入流。
        (2)使用ObjectInputStream.readObject(obj)進行讀對象。
以下是一個實現序列化與反序列化的范例:
①User類,被序列化的類:

package com.chenyu.serialable;

import java.io.Serializable;

public class User implements Serializable {

private static final long serialVersionUID = 1L;  

public int id;  
public String username;  
public String email;  

public User(int id, String username, String email) {  
    this.id = id;  
    this.username = username;  
    this.email = email;  
}   

}</code></pre>

②Test測試類,測試序列化與反序列化是否成功:

package com.chenyu.serialable;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Test {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
//實例化User類
User user =new User(1,"TestName","example@126.com");
//序列化過程
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.txt"));
objectOutputStream.writeObject(user);
objectOutputStream.close();
System.out.println("序列化成功!");
//反序列化過程
ObjectInputStream objectInputStream =new ObjectInputStream(new FileInputStream("test.txt"));
User newUser = (User) objectInputStream.readObject();
objectInputStream.close();
System.out.println("反序列化成功!");
System.out.println("ID:"+newUser.id+" username:"+newUser.username+" Email:"+newUser.email);
}
}</code></pre>

運行Test.java,得到如下結果:

Paste_Image.png


注意:靜態成員變量屬于類,而不是對象,所以不會參與序列化;使用transient關鍵字標記的成員變量不參與序列化過程。

四、Parcelable接口

        接下來我們要說的是Parcelable接口,該接口是Android提供的新的序列化方式。首先,先看官方文檔對該接口的描述:Interface for classes whose instances can be written to and restored from a Parcel. Classes implementing the Parcelable interface must also have a static field called CREATOR, which is an object implementing the Parcelable.Creator interface.
        除了實現該接口的方法外,還需創建一個名叫CREATOR的靜態對象,該對象實現了一個Parcelable.Creator的匿名內部類。以下是官方文檔的一個類實現Parcelable接口的典型例子:

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();  
 }  

}</code></pre>

        下面介紹一下以上各個方法的作用:
     ①writeToParcel(Parcel out,int flags):將當前對象寫入序列化結構之中。
     ②createFromParcel(Parcel in):從序列化后的對象中創建原始對象
     ③newArray(int size):創建指定長度的原始對象數組
     ④MyParcelable(Parcel in):從序列化后的對象中創建原始對象
     由以上各個方法可知,writeToParcel方法負責將對象序列化,而CREATOR負責數據的反序列化,只要你的類實現了Parcelable接口,并實現以上方法,那么就能自動地對對象進行序列化和反序列化了。
    注意:在writeToParcel方法中,調用了out.writeInt(data)方法,如果當前類有多個屬性,比如:int id,String name,String email,那么方法體可以寫為:

out.writeInt(id);  
out.writeString(name);  
out.writeString(email);

        這樣寫后,在相應的MyParcelable(Parcel in)反序列化方法也必須如下寫:

in.readInt();  
in.readString();  
in.readString();

        即順序應該一一對應,否則,取出來的數據將會出錯。
        到目前為止,介紹了Serialable接口和Parcelable接口,這是IPC機制中比較基礎的概念,應熟練掌握。希望我的文章能對你們的學習起到幫助作用。

來源:http://www.jianshu.com/p/3f6932db9963

 本文由用戶 mgjx5038 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!