android - parcelable教學 - serializable parcelable




使用Parcelable而不是序列化對象的好處 (6)

據我了解, BundleParcelable屬於Android執行序列化的方式。它用於例如在活動之間傳遞數據。 但是我想知道,如果在將業務對象的狀態保存到內部存儲器的情況下使用Parcelable而不是經典序列化有什麼好處? 它會比傳統方式更簡單還是更快? 我應該在哪裡使用經典序列化以及哪裡更好地使用捆綁包?


Parcelable主要與使用Binder基礎結構的IPC相關,其中數據以developer.android.com/reference/android/os/Parcel.html形式傳遞。

由於Android對大多數(即使不是全部)IPC任務的Binder依賴很多,因此在大多數地方,特別是在框架中實現Parcelable是有意義的,因為如果需要的話,它允許將對像傳遞給另一個進程。 它使物體“可運輸”。

但是,如果你有一個非Android專用業務層,它廣泛使用可序列化來保存對象狀態,並且只需要將它們存儲到文件系統中,那麼我認為可序列化就沒有問題。 它允許避免Parcelable鍋爐代碼。


Serializable在Android上非常慢。 事實上,許多情況下邊界線無用。

ParcelParcelable非常快速,但是它的documentation說明你不能將它用於通用序列化存儲,因為實現因Android的不同版本而不同(即OS更新可能會破壞依賴它的應用程序)。

以合理的速度將數據序列化到存儲的問題的最佳解決方案是自行推出。 我個人使用我自己的一個實用程序類,它有一個與Parcel類似的接口,它可以非常有效地序列化所有標準類型(以犧牲類型安全性為代價)。 這是它的一個刪節版本:

public interface Packageable {
    public void readFromPackage(PackageInputStream in)  throws IOException ;
    public void writeToPackage(PackageOutputStream out)  throws IOException ; 
}


public final class PackageInputStream {

    private DataInputStream input;

    public PackageInputStream(InputStream in) {
        input = new DataInputStream(new BufferedInputStream(in));
    }

    public void close() throws IOException {
        if (input != null) {
            input.close();
            input = null;
        }       
    }

    // Primitives
    public final int readInt() throws IOException {
        return input.readInt();
    }
    public final long readLong() throws IOException {
        return input.readLong();
    }
    public final long[] readLongArray() throws IOException {
        int c = input.readInt();
        if (c == -1) {
            return null;
        }
        long[] a = new long[c];
        for (int i=0 ; i<c ; i++) {
            a[i] = input.readLong();
        }
        return a;
    }

...

    public final String readString()  throws IOException {
        return input.readUTF();
    }
    public final <T extends Packageable> ArrayList<T> readPackageableList(Class<T> clazz) throws IOException {
        int N = readInt();
        if (N == -1) {
            return null;
        }
        ArrayList<T> list = new ArrayList<T>();
        while (N>0) {
            try {
                T item = (T) clazz.newInstance();
                item.readFromPackage(this);
                list.add(item);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            N--;
        }
        return list;
    }

}



public final class PackageOutputStream {

    private DataOutputStream output;

    public PackageOutputStream(OutputStream out) {
        output = new DataOutputStream(new BufferedOutputStream(out));
    }

    public void close() throws IOException {
        if (output != null) {
            output.close();
            output = null;
        }
    }

    // Primitives
    public final void writeInt(int val) throws IOException {
        output.writeInt(val);
    }
    public final void writeLong(long val) throws IOException {
        output.writeLong(val);
    }
    public final void writeLongArray(long[] val) throws IOException {
        if (val == null) {
            writeInt(-1);
            return;
        }
        writeInt(val.length);
        for (int i=0 ; i<val.length ; i++) {
            output.writeLong(val[i]);
        }
    }

    public final void writeFloat(float val) throws IOException {
        output.writeFloat(val);
    }
    public final void writeDouble(double val) throws IOException {
        output.writeDouble(val);
    }
    public final void writeString(String val) throws IOException {
        if (val == null) {
            output.writeUTF("");
            return;
        }
        output.writeUTF(val);
    }

    public final <T extends Packageable> void writePackageableList(ArrayList<T> val) throws IOException {
        if (val == null) {
            writeInt(-1);
            return;
        }
        int N = val.size();
        int i=0;
        writeInt(N);
        while (i < N) {
            Packageable item = val.get(i);
            item.writeToPackage(this);
            i++;
        }
    }

}


如果你需要為了存儲目的而序列化,但是想要避免由Serializable接口引起的反射的速度損失,你應該使用Externalizable接口明確地創建你自己的序列化協議。

正確實施後,這與Parcelable的速度相匹配,並且還考慮了不同版本的Android和/或Java平台之間的兼容性。

這篇文章可能也會清楚一些事情:

Java中的Serializable和Externalizable有什麼區別?

在旁注中,它也是許多基準測試中速度最快的序列化技術,擊敗了Kryo,Avro,Protocol Buffers和Jackson(json):

http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking


我只是使用GSON - >序列化到JSON字符串 - >從JSON字符串恢復對象。


現在看來,這種差異並不那麼明顯,至少不是在你自己的活動之間運行時。

根據developerphil.com/parcelable-vs-serializable上顯示的測試,Parcelable在新設備上的速度(如nexus 10)要快10倍左右,而老設備上的速度要快17左右(如願望Z)

所以由您決定是否值得。

也許對於相對較小和簡單的類來說,Serializable很好,而對於其他的,你應該使用Parcelable





parcelable