歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android中的Parcelable接口

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

Android中的數據傳遞之parcelable接口 http://www.linuxidc.com/Linux/2013-05/84333p2.htm

比如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對象即可:

1 ParcelableName name = getArguments().getParcelable("name");
不過,既然Java已經有了Serializable,那還需要Parcelable干什麼呢?而且Serializable接口使用起來也非常簡潔。


原因有三個,第一是效率,第二是效率,第三還是效率:
1.Serializable用了很多反射,細心的人都知道,反射比正常的調用要慢100多倍

2.Serializable會創建很多臨時對象,這些臨時對象會導致很多次垃圾回收,影響效率

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

下面是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接口的,畢竟編碼和維護的代價都小得多。

Ubuntu 14.04 x64配置Android 4.4 kitkat編譯環境的方法 http://www.linuxidc.com/Linux/2014-05/101148.htm

Ubuntu 12.04搭建Android開發環境 http://www.linuxidc.com/Linux/2012-09/69961.htm

Ubuntu 14.04 配置 Android SDK 開發環境 http://www.linuxidc.com/Linux/2014-05/101039.htm

64位Ubuntu 11.10下Android開發環境的搭建(JDK+Eclipse+ADT+Android SDK詳細) http://www.linuxidc.com/Linux/2013-06/85303.htm

Ubuntu 12.10 x64 安裝 Android SDK http://www.linuxidc.com/Linux/2013-03/82005.htm

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved