使用Parcelable而不是序列化对象的好处

时间:2011-04-05 10:53:21

标签: android serialization bundle parcelable

据我了解,BundleParcelable属于Android执行序列化的方式。例如,它用于在活动之间传递数据。但我想知道,如果在将业务对象的状态保存到内部存储器的情况下使用Parcelable而不是经典序列化有什么好处?它会比传统方式更简单或更快吗?我应该在哪里使用经典序列化以及哪里更好地使用bundle?

9 个答案:

答案 0 :(得分:100)

来自“Pro Android 2”

  

注意:看到Parcelable可能触发了这个问题,为什么Android没有使用       内置的Java序列化机制?事实证明,   Android团队得出结论       Java中的序列化太慢而无法满足Android的要求   进程间通信       要求。因此团队构建了Parcelable解决方案。该   可行的方法需要       您明确序列化您的类的成员,但最后,   你得到更快       序列化您的对象。

     

还要意识到Android提供了两种允许您通过的机制   数据到另一个       处理。第一种是使用intent将包传递给活动,   第二是通过       可分配给服务。这两种机制不可互换   不应该是       困惑。也就是说,Parcelable并不意味着传递给   活动。如果你想开始       一个活动并传递一些数据,使用一个包。 Parcelable意为   仅作为一部分使用       AIDL定义。

答案 1 :(得分:22)

在Android上,

Serializable显然很慢。事实上,在许多情况下,边界无用。

ParcelParcelable非常快,但documentation表示您不得将其用于存储的通用序列化,因为实施因Android的不同版本而异(即操作系统更新可能会破坏依赖它的应用程序。)

以合理的速度将数据序列化到存储的问题的最佳解决方案是自行推送。我个人使用我自己的一个实用程序类,它具有与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++;
        }
    }

}

答案 2 :(得分:11)

查看Parcelable的速度与Serializable相比有多快。

enter image description here

来自WHY WE LOVE PARCELABLE

enter image description here

来自Parcelable vs Serializable

答案 3 :(得分:10)

如果您需要序列化以用于存储目的但希望避免可序列化接口引起的反射速度损失,则应使用可外部化明确创建自己的序列化协议接口

如果正确实施,这与Parcelable的速度相匹配,并且还考虑了不同版本的Android和/或Java平台之间的兼容性。

这篇文章也可以解决问题:

What is the difference between Serializable and Externalizable in Java?

在旁注中,它也是许多基准测试中最快的序列化技术,击败了Kryo,Avro,Protocol Buffers和Jackson(json):

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

答案 4 :(得分:7)

现在看来差异并不那么明显,至少在你自己的活动之间没有这种差异时。

根据this website上显示的测试,Parcelable在最新设备(如nexus 10)上快10倍,在旧版设备上快17(如欲望Z)

所以由你决定是否值得。

对于相对较小且简单的类,Serializable很好,其余的,你应该使用Parcelable

答案 5 :(得分:4)

Parcelable主要与使用Binder基础设施的IPC相关,其中数据以Parcels传递。

由于Android在大多数(如果不是全部)IPC任务中都依赖于Binder,因此在大多数地方,特别是在框架中实现Parcelable是有意义的,因为它允许在需要时将对象传递给另一个进程。它使对象“可移动”。

但是如果你有一个非特定于Android的业务层,它广泛使用可序列化来保存对象状态,并且只需要将它们存储到文件系统,那么我认为可序列化很好。它允许避免使用Parcelable样板代码。

答案 6 :(得分:1)

基于这篇文章http://www.mooproductions.org/node/6?page=5 Parcelable应该更快。

文章中没有提到,我并不认为可序列化对象可以在AIDL中用于远程服务。

答案 7 :(得分:1)

我只使用GSON - &gt;序列化为JSON字符串 - &gt;从JSON字符串还原对象。

答案 8 :(得分:0)

此外,Parcelable提供了自定义实现,用户可以通过覆盖writeToParcel()获得包裹其每个对象的机会。但序列化并不是这种自定义实现,因为它传递数据的方式涉及JAVA反射API。