7.Serializable和Parcelable

Serializable和Parcelable接口可以完成對象的序列化過程,當我們需用使用Intent 和Binder 傳輸數據的時候,就需要使用到Parcel和Serializable.而有時候,我們需要持久化數據、或者是傳輸數據到網絡上,我們也要使用Serializable來完成對象的序列化。
    
    7.1Serializable接口
    實現序列化接口,很簡單,只需要實現它,就好,當然,最好是賦予它一個serialVersionUId (序列化ID)。不聲明序列化ID,其實也可以序列化,但是,可能會對反序列化有影響。下面我們就簡單介紹序列化和反序列化的過程:
        假設我們有一個User類如下:
        
public class User impelements Serializable{
        
            private static final long serialVersionUID = 519606712346586214L;

            public int userId;
            public String userName;
            
        }


        序列化過程需要用到ObjectOutputStream下面是序列化的過程:
        
        
User user = new User();
        user.userId= 12;
        user.userName = "張三";

        ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( "cache.txt") );
        out.writeObject( user );
        out.close();


        通過上面的代碼,對象就序列化到了cache.txt文件上了。
        而這時候,我們希望能夠把文件在變成對象,該怎麼做呢?
        就要進行反序列化過程,序列化的過程我們是使用ObjectOutputStream 那麼反序列化當然是用ObjectInputStream
        
 ObjectInputStream in = new ObjectOutputStream( new FileInputStream( "cache.txt"));
         in.readObject();
         in.close();

         通過上面的代碼,我們就能把對象從文件當中恢復,恢復出來的內容是完全一樣的,但是他們不是同一個對象。
         現在,我們在這邊來討論下serialVersionUID的作用吧,首先,就要從反序列化過程入手:
         反序列化的時候,系統會查看文件的序列化ID,如果序列化ID一致,那麼就會進行序列化,因爲這代表對象是一樣的,反之,則不會,因爲序列化ID不一樣說明了這個類已經被改變了,比如成員數量變化、類型變化,這時候就會反序列化失敗。一般來說,我們要手動指定UID值,或者是用Eclipse等工具在創建的時候自動生成一個hash值,如果我們不指定會怎麼樣?不指定的話,系統序列化的時候,會把當前類的hash值作爲序列化ID,那麼當我們反序列化的時候,如果這個類改變了,那麼hash值就會改變,那麼就會造成序列化ID不一樣,那麼就導致了反序列化失敗。
        簡單地說,不指定ID的話,我們存儲User 時候有2個變量,而我們想獲取原來User的數據的時候,我們改變了User類,改成了3個變量.增加了學號:number
這時候,從cache.txt想反序列化是不行的,因爲cache的那個User是2個變量的User ,2個變量的User和3個變量的User的hash值改變了,所以系統認爲兩個不是一個版本的類,所以反序列化失敗。
    值得一提的是,序列化ID一樣,並不一定會保證反序列化成功,比如我把userName從String改成了int,這樣就會破壞了類的結構,或者是我改了類名也會造成這種情況。

    7.2Parcelable接口
        Parcelable也是一個接口,只要實現這個接口,這個類的對象就可以實現序列化,並且可以通過Intent和Biner進行傳遞。
        下面是實現了Parcelable的例子:
public class User implements Parcelable {

    public int userId;
    public String userName;
    public boolean isMale;

    public Book book;

    public User( int userId, String userName , boolean isMale )
    {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;

    }

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

    @Override
    public void writeToParcel(Parcel out, int arg1) {

        out.writeInt( userId );
        out.writeString(userName);
        out.writeInt( isMale ? 1:0 );
        out.writeParcelable(book, 0);
    }

    public Parcelable.Creator< User> CREATOR = new Parcelable.Creator<User>() {

        @Override
        public User createFromParcel(Parcel arg0) {
             return new User(arg0) ;
        }

        @Override
        public User[] newArray(int arg0) {
            // TODO Auto-generated method stub
            return new User[arg0];
        }
    };

    private User( Parcel in )
    {
        userId = in.readInt();
        userName = in.readString();
        isMale = in.readInt() == 1 ? true : false;
        book = in.readParcelable( Thread.currentThread().getContextClassLoader());
    }
}


可以看到,反序列化的過程是由CREATOR來實現的。
        系統已經爲我們提供了很多實現了Parcelable的類,它們都是可以直接序列化的,比如Intent、Bundle、Bitmap等,
 同時List和Map也可以序列化,前提是它們裏面的每個元素都是可以序列化的。
        Serializable是Java的接口,它使用起來比較簡單,但是開銷大,因爲需要大量的I/O操作。而Parcel是Anroid多肚餓,他的效率比較高,適合用在內存交換當中,而如果是持久化數據或者是網路傳輸,採用Serializble比較好,因爲Parcel實現比較複雜(也是可以持久化和傳輸)。
   

    
    
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章