Android中的Parcelable介面

來源:互聯網
上載者:User

標籤:fragment訊息專遞   android序列化   serializable   parcelable   

Android中的android.os.Parcelable介面用於替代Java序列化Serializable介面,Fragment以及Activtity之間都需要傳遞資料,有時甚至包含結構非常複雜的對象,這就需要先將這個對象序列化成二進位流,然後再進行傳遞了。


比如Fragment1向Fragment2傳遞資料,下面是Fragment1中建立Fragment2並傳送資料的方法:

Fragment2 fragment = new Fragment2();Bundle bundle = new Bundle();bundle.putParcelable("name", name);fragment2.setArguments(bundle);    FragmentManager fm = getFragmentManager();FragmentTransaction ft = getFragmentManager().beginTransaction();ft.replace(R.id.container, fragment2)            .addToBackStack(null)            .commit();

在Fragment2中,直接得到這個Parcelable對象即可:

ParcelableName name = getArguments().getParcelable("name");

不過,既然Java已經有了Serializable,那還需要Parcelable幹什麼呢?而且Serializable介面使用起來也非常簡潔。


原因有三個,第一是效率,第二是效率,第三還是效率:

  1. Serializable用了很多反射,細心的人都知道,反射比正常的調用要慢100多倍

  2. Serializable會建立很多臨時對象,這些臨時對象會導致很多次記憶體回收,影響效率


有細心的人士做過測試,基本上Parcelable要比Serializable快上10-20倍。下面這個圖是比較結構,更詳細資料可以參考Parcelable vs Serializable

650) this.width=650;" src="http://www.developerphil.com/wp-content/uploads/2013/04/parcelable-vs-serializable.png" />

下面是android.os.Parcelable介面的定義,相比java.io.Serializable要複雜很多,不過,為了效率,你也只能忍了。

public interface Parcelable {    public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;    public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;    public int describeContents();    public void writeToParcel(Parcel dest, int flags);         public interface Creator<T> {        public T createFromParcel(Parcel source);        public T[] newArray(int size);    }         public interface ClassLoaderCreator<T> extends Creator<T> {        public T createFromParcel(Parcel source, ClassLoader loader);    }}

看起來你至少需要實現兩個方法describeContents()和writeToParcel():

  1. 第一個方法返回數字,一般返回0就好,只有FileDescriptor有特殊,上面的常量有定義。至於這有什麼用,我也沒有找到相關的資訊,如果有讀者理解,請留言告知我。

  2. 第二個方法用於將對象寫入到Parcel對象中。詳見下面的例子。


接著自己來實現一個包含了姓和名兩個String欄位的對象,如下:

    import android.os.Parcel;    import android.os.Parcelable;     public class ParcelableName implements Parcelable {        private String mSurname;        private String mGivenName;             public ParcelableName(String surname, String givenName) {            mSurname = surname;            mGivenName = givenName;        }             // 私人方法,因為我們不應該將參數是Parcel的建構函式暴露出去        private ParcelableName(Parcel source) {            this(source.readString(), source.readString());        }             @Override        public int describeContents() {            return 0;        }             public String getSurname() {            return mSurname;        }             public String getGivenName() {            return mGivenName;        }             @Override        public void writeToParcel(Parcel dest, int flags) {            dest.writeString(mSurname);            dest.writeString(mGivenName);        }            // 通過這個介面來建立Parcel對象,調用了私人的建構函式        public static final Parcelable.Creator<ParcelableName> CREATOR             = new Creator<ParcelableName>() {                 @Override            public ParcelableName createFromParcel(Parcel source) {                return new ParcelableName(source);            }                 @Override            public ParcelableName[] newArray(int size) {                return new ParcelableName[0];            }        };    }

這裡使用了Parcel.writeString()方法來將一個對象寫入到序列化對象中,使用了Parcel.readString()從序列化對象中讀取資料,一定要注意的是這裡的寫入和讀取是有順序的:先寫的要先讀。


注意,這裡我們建立了一個私人的建構函式,這個建構函式的參數是Parcel對象,我們還建立了一個CREATOR的類變數,這個對象專門用於從序列化對象中建立ParcelableName對象,這是為了儘可能向外界隱藏序列化對象的實現細節,這種方式需要仔細琢磨,才能有所領悟。

值得提一下的是,Parcelable介面中還有一個ClassLoaderCreator介面,裡面的createFromParcel()的第二個參數是一個ClassLoader對象,意味著我們可以還原序列化不同的ClassLoader中的對象。

擷取這段代碼可以到:https://gist.github.com/zhlwish/3e2bbe9a15edf3b84ef7

這種代碼寫起來的確是挺麻煩的,有一個開源項目Parceler通過Anotation+代碼產生的方法可以簡化定義Parcelable對象的過程:


    @Parcel    public class Example {        String mSurname;        String mGivenName;            public Example(){ }            public Example(String surname, String givenName) {            mSurname = surname;            mGivenName = givenName;        }            public String getSurname() { return mSurname; }        public String getGivenName() { return mGivenName; }    }

看起來簡單多了,不過話說回來,如果你需要序列化的對象比較小,而且次數不多,不影響效率,你還是可以繼續使用Serializable介面的,畢竟編碼和維護的代價都小得多。


本文出自 “深入淺出Android” 部落格,請務必保留此出處http://androidigging.blog.51cto.com/2753843/1426767

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.