99

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

4

9 回答 9

101

来自“Pro Android 2”

注意:看到 Parcelable 可能会引发问题,为什么 Android 不使用内置的 Java 序列化机制?事实证明,Android 团队得出的结论是,Java 中的序列化速度太慢,无法满足 Android 的进程间通信要求。因此,该团队构建了 Parcelable 解决方案。Parcelable 方法要求您显式序列化类的成员,但最终,您可以更快地序列化对象。

还要意识到 Android 提供了两种机制,允许您将数据传递给另一个进程。第一种是使用意图将捆绑包传递给活动,第二种是将 Parcelable 传递给服务。这两种机制不可互换,不应混淆。也就是说,Parcelable 并不意味着传递给活动。如果您想启动一个活动并传递一些数据,请使用捆绑包。Parcelable 仅用作 AIDL 定义的一部分。

于 2011-04-05T11:35:33.517 回答
23

Serializable在 Android 上速度慢得可笑。事实上,边界线在很多情况下是无用的。

Parcel并且Parcelable速度非常快,但它的文档说你不能将它用于通用序列化到存储,因为实现会随 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++;
        }
    }

}
于 2011-04-10T07:48:58.343 回答
13

看看Parcelable比 Serializable 快得多。


在此处输入图像描述

我们为什么喜欢 PARCELABLE


在此处输入图像描述

Parcelable 与 Serializable

于 2015-08-28T08:32:02.533 回答
11

如果您需要序列化用于存储目的,但又想避免Serializable接口引起的反射速度损失,您应该使用Externalizable接口显式创建您自己的序列化协议。

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

这篇文章也可能会澄清一些事情:

Java中的可序列化和可外部化有什么区别?

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

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

于 2012-02-08T15:20:49.047 回答
7

现在看来,这种差异并不那么明显,至少当您在自己的活动之间运行它时不会如此。

根据本网站上显示的测试,Parcelable 在最新设备(如 nexus 10)上快了约 10 倍,在旧设备(如欲望 Z)上快了约 17 倍

所以由你决定是否值得。

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

于 2014-02-26T12:05:07.883 回答
4

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

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

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

于 2011-04-08T18:43:34.530 回答
1

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

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

于 2011-04-05T11:23:38.790 回答
1

我只是使用 GSON -> 序列化为 JSON 字符串 -> 从 JSON 字符串恢复对象。

于 2016-09-10T13:22:54.200 回答
0

Parcelable 还提供自定义实现,用户有机会通过覆盖 writeToParcel() 来打包他的每个对象,但是序列化并没有这种自定义实现,因为它传递数据的方式涉及 JAVA 反射 API。

于 2017-04-11T10:22:19.940 回答