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

Vla*_*nov 97 serialization android bundle parcelable

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

raj*_*ath 100

来自"Pro Android 2"

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

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

  • 第二段不是真的,你可以使用bundle将Parcelable作为参数传递给一个活动...... (78认同)
  • 什么是"Pro Android 2"? (9认同)
  • Philippe Breault发表了一篇很好的文章,并且还增加了性能测试.http://www.developerphil.com/parcelable-vs-serializable/ (4认同)
  • 当我序列化我的对象时,我创建一个`getBundle`方法,然后从`writeToParcel`调用它作为`dest.writeBundle(getBundle());`并且我自动在对象中有两个选项.这里有一些有趣的Parcel功能,包括:http://developer.android.com/reference/android/os/Parcel.html (3认同)
  • @lxx:我想知道为什么需要通过bundle将parcelable对象传递给activity.IMO,如果你这样做,你不必要地添加一个更多级别的序列化,没有别的. (2认同)

Reu*_*ton 22

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++;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 使用你的这个自定义类和仅仅实现 Externalizable 接口并做同样的事情有什么区别? (2认同)
  • 我认为开头的句子不再是真的(制作完成后5年).很长一段时间以来,我一直在使用java序列化而没有任何问题.您可以在我刚刚撰写的博客文章中找到关于此主题的一些可能有趣的内容.http://nemanjakovacevic.net/blog/english/2015/03/24/yet-another-post-on-serializable-vs-parcelable/ (2认同)

whi*_*row 10

如果您需要序列化以进行存储,但希望避免Serializable接口引起的反射速度损失,则应使用Externalizable接口显式创建自己的序列化协议.

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

这篇文章也可能会澄清:

Java中的Serializable和Externalizable有什么区别?

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

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


and*_*per 7

现在似乎差异并不那么明显,至少在你自己的活动之间运行它时.

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

所以由你来决定它是否值得.

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