【Android】序列化方式Serializable和Parcelable

開始

爲何須要序列化,由於Java進程間通信數據不能直接傳遞,必需進行序列化傳遞在拿到序列化以後再反序列化拿到本來數據。而在Android開發中同一個應用程序中Intent傳遞的對象都須要序列化!其中有跨進程的操做嗎?
實際上在Android開發中,Activity A啓動Activity B經過Intent傳遞數據。在這個過程當中須要離開應用程序所在進程,轉而調用native方法進入linux kernel進程中執行Activity切換的實際操做。所以在這個過程當中數據是跨進程進行的,因此須要對傳遞的對象進行序列化操做。
<!--more-->html

Serializable

Serializable是在包java.io下,它是interface。
打開源碼一看,一臉懵。什麼啊接口爲空,啥都沒。它是怎麼序列化的?java

public interface Serializable {
}

看看官方介紹吧,implements Serializable的類能夠經過ObjectOutputStream序列化,經過ObjectInputStream反序列化。那咱們就經過源碼看看大致上是如何經過兩個類去作序列化和反序列化。linux

ObjectOutputStream

ObjectOutputStream繼承於抽象類OutputStream。對於對Serializable序列化過程在write方法下,在writeObject方法中有一個writeObject0,下面講一下它。
ObjectOutputStream支持對Serializable類型的Object寫操做。在方法中會去執行writeOrdinaryObject去對Serializable作寫操做。而後在writeOrdinaryObject中能夠看到會去判斷對象是Externalizable仍是Serializable,根據類型不一樣在去作不一樣的寫操做。Externalizable是Serializable的子類,它提供兩個接口方法:writeExternal、readExternal。後面就不在繼續分析,以後若是有時間在細化解讀。android

...
            if (obj instanceof Class) {
                writeClass((Class) obj, unshared);
            } else if (obj instanceof ObjectStreamClass) {
                writeClassDesc((ObjectStreamClass) obj, unshared);
            // END Android-changed
            } else if (obj instanceof String) {
                writeString((String) obj, unshared);
            } else if (cl.isArray()) {
                writeArray(obj, desc, unshared);
            } else if (obj instanceof Enum) {
                writeEnum((Enum<?>) obj, desc, unshared);
            } else if (obj instanceof Serializable) {
                writeOrdinaryObject(obj, desc, unshared);
            } else {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                        cl.getName() + "\n" + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }
...

private void writeOrdinaryObject(Object obj,
                                     ObjectStreamClass desc,
                                     boolean unshared)
        throws IOException
    {
        if (extendedDebugInfo) {
            debugInfoStack.push(
                (depth == 1 ? "root " : "") + "object (class \"" +
                obj.getClass().getName() + "\", " + obj.toString() + ")");
        }
        try {
            desc.checkSerialize();

            bout.writeByte(TC_OBJECT);//BlockDataOutputStream寫入類型標記該對象爲TC_OBJECT
            writeClassDesc(desc, false);
            handles.assign(unshared ? null : obj);
            if (desc.isExternalizable() && !desc.isProxy()) {
                writeExternalData((Externalizable) obj);
            } else {
                writeSerialData(obj, desc);
            }
        } finally {
            if (extendedDebugInfo) {
                debugInfoStack.pop();
            }
        }
    }

ObjectInputStream

ObjectOutputStream繼承於抽象類OutputStream。對應ObejctOutStream,對Seriallizable的反序列化過程在readObejct中。一樣readObejct有readObject0。readObject0下面咱們很清楚的看到一樣有readOrdinaryObject。在readOrdinaryObject仍是和上述同樣會去判斷是Serializable仍是子類Externalizable去執行不一樣的讀取方法。細化部分還有不少內容能夠將咱們仍是跳過,這裏點到爲止。segmentfault

private Object readObject0(boolean unshared) throws IOException {
      ...
        depth++;
        try {
            switch (tc) {
                case TC_NULL:
                    return readNull();

                case TC_REFERENCE:
                    return readHandle(unshared);

                case TC_CLASS:
                    return readClass(unshared);

                case TC_CLASSDESC:
                case TC_PROXYCLASSDESC:
                    return readClassDesc(unshared);

                case TC_STRING:
                case TC_LONGSTRING:
                    return checkResolve(readString(unshared));

                case TC_ARRAY:
                    return checkResolve(readArray(unshared));

                case TC_ENUM:
                    return checkResolve(readEnum(unshared));

                case TC_OBJECT://經過BlockDataInputStream的peekByte拿到對象類型知道該對象爲Serializable
                    return checkResolve(readOrdinaryObject(unshared));

           ....
    }


        private Object readOrdinaryObject(boolean unshared)                                 
        throws IOException                                                              
    {                                                                                   
        if (bin.readByte() != TC_OBJECT) {                                              
            throw new InternalError();                                                  
        }                                                                               
                                                                                        
        ObjectStreamClass desc = readClassDesc(false);                                  
        desc.checkDeserialize();                                                        
                                                                                        
        Class<?> cl = desc.forClass();                                                  
        if (cl == String.class || cl == Class.class                                     
                || cl == ObjectStreamClass.class) {                                     
            throw new InvalidClassException("invalid class descriptor");                
        }                                                                               
                                                                                        
        Object obj;                                                                     
        try {                                                                           
            obj = desc.isInstantiable() ? desc.newInstance() : null;                    
        } catch (Exception ex) {                                                        
            throw (IOException) new InvalidClassException(                              
                desc.forClass().getName(),                                              
                "unable to create instance").initCause(ex);                             
        }                                                                               
                                                                                        
        passHandle = handles.assign(unshared ? unsharedMarker : obj);                   
        ClassNotFoundException resolveEx = desc.getResolveException();                  
        if (resolveEx != null) {                                                        
            handles.markException(passHandle, resolveEx);                               
        }                                                                               
                                                                                        
        if (desc.isExternalizable()) {//判斷是子類仍是Serializable自己                                                  
            readExternalData((Externalizable) obj, desc);                               
        } else {                                                                        
            readSerialData(obj, desc);                                                  
        }                                                                               
                                                                                        
        handles.finish(passHandle);                                                     
                                                                                        
        if (obj != null &&                                                              
            handles.lookupException(passHandle) == null &&                              
            desc.hasReadResolveMethod())                                                
        {                                                                               
            Object rep = desc.invokeReadResolve(obj);                                   
            if (unshared && rep.getClass().isArray()) {                                 
                rep = cloneArray(rep);                                                  
            }                                                                           
            if (rep != obj) {                                                           
                handles.setObject(passHandle, obj = rep);                               
            }                                                                           
        }                                                                               
                                                                                        
        return obj;                                                                     
    }
  • Serializable在序列化中開銷比較大,過程會產生大量臨時變量,從而引發頻繁的GC。雖然Serializable能夠將數據持久化,但內存序列化太佔用資源。
  • 靜態成員變量屬於類不屬於對象所以不參與序列化過程。
  • transient能夠屏蔽特殊數據成員不參與序列化。
serialVersionUID的詳細工做機制是這樣的:序列化的時候系統會把當前類的serialVersionUID寫入序列化的文件中,當反序列化的時候系統會去檢查文件中的serialVersionUID,看它是否和當前類的serialVersionUID一致,若是一致說明序列化的類版本與當前類的版本是相同的則能夠成功反序列化。最好是實現Serializable接口的對象添加UID,若反序列化時原有類發生改變,增長或刪除某些成員變量,那麼系統要從新計算當前類的hash值。然而當前是UID和序列化數據的UID對應不上會出現反序列失敗。

Parcelable

Parcelable是在包android.os下的,一樣它也是interface。話說Android設計Parcelable初衷就是由於Serializable序列化效率慢。並且Android不少類都實現Parcelable接口。網絡

@Retention(RetentionPolicy.SOURCE)
    public @interface ContentsFlags {}
    public @ContentsFlags int describeContents();
    public void writeToParcel(Parcel dest, @WriteFlags 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);
    }

下面的DrivderParcelable實現Parcelable接口,能夠看到類成員寫入Parcel和從Parcel讀出順序必須保持一致。ide

public class DrivderParcelable implements Parcelable{

    private String name;
    private String address;
    private String carName;

    public DrivderParcelable(String name, String address, String carName) {
        this.name = name;
        this.address = address;
        this.carName = carName;
    }


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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
        dest.writeString(this.address);
        dest.writeString(this.carName);
    }

    protected DrivderParcelable(Parcel in) {
        this.name = in.readString();
        this.address = in.readString();
        this.carName = in.readString();
    }

    public static final Creator<DrivderParcelable> CREATOR = new Creator<DrivderParcelable>() {
        @Override
        public DrivderParcelable createFromParcel(Parcel source) {
            return new DrivderParcelable(source);
        }

        @Override
        public DrivderParcelable[] newArray(int size) {
            return new DrivderParcelable[size];
        }
    };
}

Parcel

其實實現Parcelable接口,其中讀寫方法還都是在Parcel中。writeToParcel是序列化過程方法,ClassLoaderCreator是反序列化過程,因此Parcelable序列化過程都是交給Parcel實現的。查看Parcel源碼會發現,不少方法在native層實現的,甚至讀寫方法。這也可能就是爲何Parcelable比起Serializable效率更高的緣由吧。(我的猜測)this

...
    private static native void nativeWriteDouble(long nativePtr, double val);
    private static native void nativeWriteString(long nativePtr, String val);
    private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
    private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
...
    @FastNative
    private static native int nativeReadInt(long nativePtr);
    @FastNative
    private static native long nativeReadLong(long nativePtr);
    @FastNative
    private static native float nativeReadFloat(long nativePtr);
    @FastNative
    private static native double nativeReadDouble(long nativePtr);
    private static native String nativeReadString(long nativePtr);
...

另外會發現Parcel支持寫入的對象不少,包括Serializable、IBinder。相比較比ObjectOutputStream更爲強大啊!.net

public final void writeValue(Object v) {
        if (v == null) {
            writeInt(VAL_NULL);
        } else if (v instanceof String) {
            writeInt(VAL_STRING);
            writeString((String) v);
        } else if (v instanceof Integer) {
            writeInt(VAL_INTEGER);
            writeInt((Integer) v);
        } else if (v instanceof Map) {
            writeInt(VAL_MAP);
            writeMap((Map) v);
        } else if (v instanceof Bundle) {
            // Must be before Parcelable
            writeInt(VAL_BUNDLE);
            writeBundle((Bundle) v);
        } else if (v instanceof PersistableBundle) {
            writeInt(VAL_PERSISTABLEBUNDLE);
            writePersistableBundle((PersistableBundle) v);
        } else if (v instanceof Parcelable) {
            // IMPOTANT: cases for classes that implement Parcelable must
            // come before the Parcelable case, so that their specific VAL_*
            // types will be written.
            writeInt(VAL_PARCELABLE);
            writeParcelable((Parcelable) v, 0);
        } else if (v instanceof Short) {
            writeInt(VAL_SHORT);
            writeInt(((Short) v).intValue());
        } else if (v instanceof Long) {
            writeInt(VAL_LONG);
            writeLong((Long) v);
        } else if (v instanceof Float) {
            writeInt(VAL_FLOAT);
            writeFloat((Float) v);
        } else if (v instanceof Double) {
            writeInt(VAL_DOUBLE);
            writeDouble((Double) v);
        } else if (v instanceof Boolean) {
            writeInt(VAL_BOOLEAN);
            writeInt((Boolean) v ? 1 : 0);
        } else if (v instanceof CharSequence) {
            // Must be after String
            writeInt(VAL_CHARSEQUENCE);
            writeCharSequence((CharSequence) v);
        } else if (v instanceof List) {
            writeInt(VAL_LIST);
            writeList((List) v);
        } else if (v instanceof SparseArray) {
            writeInt(VAL_SPARSEARRAY);
            writeSparseArray((SparseArray) v);
        } else if (v instanceof boolean[]) {
            writeInt(VAL_BOOLEANARRAY);
            writeBooleanArray((boolean[]) v);
        } else if (v instanceof byte[]) {
            writeInt(VAL_BYTEARRAY);
            writeByteArray((byte[]) v);
        } else if (v instanceof String[]) {
            writeInt(VAL_STRINGARRAY);
            writeStringArray((String[]) v);
        } else if (v instanceof CharSequence[]) {
            // Must be after String[] and before Object[]
            writeInt(VAL_CHARSEQUENCEARRAY);
            writeCharSequenceArray((CharSequence[]) v);
        } else if (v instanceof IBinder) {
            writeInt(VAL_IBINDER);
            writeStrongBinder((IBinder) v);
        } else if (v instanceof Parcelable[]) {
            writeInt(VAL_PARCELABLEARRAY);
            writeParcelableArray((Parcelable[]) v, 0);
        } else if (v instanceof int[]) {
            writeInt(VAL_INTARRAY);
            writeIntArray((int[]) v);
        } else if (v instanceof long[]) {
            writeInt(VAL_LONGARRAY);
            writeLongArray((long[]) v);
        } else if (v instanceof Byte) {
            writeInt(VAL_BYTE);
            writeInt((Byte) v);
        } else if (v instanceof Size) {
            writeInt(VAL_SIZE);
            writeSize((Size) v);
        } else if (v instanceof SizeF) {
            writeInt(VAL_SIZEF);
            writeSizeF((SizeF) v);
        } else if (v instanceof double[]) {
            writeInt(VAL_DOUBLEARRAY);
            writeDoubleArray((double[]) v);
        } else {
            Class<?> clazz = v.getClass();
            if (clazz.isArray() && clazz.getComponentType() == Object.class) {
                // Only pure Object[] are written here, Other arrays of non-primitive types are
                // handled by serialization as this does not record the component type.
                writeInt(VAL_OBJECTARRAY);
                writeArray((Object[]) v);
            } else if (v instanceof Serializable) {
                // Must be last
                writeInt(VAL_SERIALIZABLE);
                writeSerializable((Serializable) v);
            } else {
                throw new RuntimeException("Parcel: unable to marshal value " + v);
            }
        }
    }

所以能夠猜到實現Parcelable接口對象中的成員變量能夠是實現Serializable接口的對象。但子類實現的接口必需和父類統一,不然序列化失敗。插件

  • 比起Serializable,Parcelable開銷更小效率更高。
  • 序列化過程較複雜。其實實現Parcelable接口的方法是能夠用插件直接生成的。
  • Parcelable實現主要仍是解決Android平臺內存緊缺的問題。

最後

總結來講Serializable更適合穩定的數據傳遞、持久化以及網絡傳輸,主要仍是由於Parcelable是有Android開發而產生可能在多個版本中存在差別,爲了兼容性以及穩定性作好選擇Serializable。Parcelable雖然實現複雜,但它更高效,佔用內存小,所以適合在內存序列化中使用,例如Activity間通訊和AIDL數據傳遞。

參考

相關文章
相關標籤/搜索