Android:Parcelable 和 Serializable 之间的区别?

410
为什么Android提供了两个接口来序列化对象?可序列化的对象与Android Binder和AIDL文件相互操作吗?
16个回答

577
在Android中,我们不能直接将对象传递给活动。为了做到这一点,对象必须实现SerializableParcelable 接口。 Serializable Serializable是一个标准的Java接口。您可以实现Serializable接口并添加覆盖方法。这种方法的问题在于它使用反射,并且速度很慢。此方法创建大量临时对象并导致相当多的垃圾回收。但是,Serializable 接口更容易实现。
请看下面的示例(Serializable):
// MyObjects Serializable class

import java.io.Serializable;
import java.util.ArrayList;
import java.util.TreeMap;

import android.os.Parcel;
import android.os.Parcelable;

public class MyObjects implements Serializable {

    private String name;
    private int age;
    public ArrayList<String> address;

    public MyObjects(String name, int age, ArrayList<String> address) {
        super();
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public ArrayList<String> getAddress() {
        if (!(address == null))
            return address;
        else
            return new ArrayList<String>();
    }

    public String getName() {
        return name;
    }

    // return age
    public int getAge() {
        return age;
    }
}

// MyObjects instance
MyObjects mObjects = new MyObjects("name", "age", "Address array here");

// Passing MyObjects instance via intent
Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putExtra("UniqueKey", mObjects);
startActivity(mIntent);

// Getting MyObjects instance
Intent mIntent = getIntent();
MyObjects workorder = (MyObjects)    mIntent.getSerializableExtra("UniqueKey");

Parcelable

Parcelable 过程比 Serializable 更快。其中一个原因是我们明确了序列化过程,而不是使用反射来推断它。此外,代码已经针对此目的进行了大量优化。

请查看以下示例 (Parcelable):

// MyObjects Parcelable class

import java.util.ArrayList;

import android.os.Parcel;
import android.os.Parcelable;

public class MyObjects implements Parcelable {

    private int age;
    private String name;
    private ArrayList<String> address;

    public MyObjects(String name, int age, ArrayList<String> address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public MyObjects(Parcel source) {
        age = source.readInt();
        name = source.readString();
        address = source.createStringArrayList();
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(age);
        dest.writeString(name);
        dest.writeStringList(address);
    }

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public ArrayList<String> getAddress() {
        if (!(address == null))
            return address;
        else
            return new ArrayList<String>();
    }

    public static final Creator<MyObjects> CREATOR = new Creator<MyObjects>() {
        @Override
        public MyObjects[] newArray(int size) {
            return new MyObjects[size];
        }

        @Override
        public MyObjects createFromParcel(Parcel source) {
            return new MyObjects(source);
        }
    };
}

// MyObjects instance
MyObjects mObjects = new MyObjects("name", "age", "Address array here");

// Passing MyOjects instance
Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putExtra("UniqueKey", mObjects);
startActivity(mIntent);

// Getting MyObjects instance
Intent mIntent = getIntent();
MyObjects workorder = (MyObjects) mIntent.getParcelableExtra("UniqueKey");

您可以按以下方式传递 Parcelable 对象的 ArrayList
// Array of MyObjects
ArrayList<MyObjects> mUsers;

// Passing MyOjects instance
Intent mIntent = new Intent(FromActivity.this, ToActivity.class);
mIntent.putParcelableArrayListExtra("UniqueKey", mUsers);
startActivity(mIntent);

// Getting MyObjects instance
Intent mIntent = getIntent();
ArrayList<MyObjects> mUsers = mIntent.getParcelableArrayList("UniqueKey");

结论

  1. Parcelable 接口比 Serializable 接口更快。
  2. Parcelable 接口相比于 Serializable 接口需要更多的时间来实现。
  3. Serializable 接口比较容易实现。
  4. Serializable 接口会创建大量临时对象,并引起很多垃圾回收。
  5. Parcelable 数组可以通过 Intent 在 Android 中传递。

5
@Sujith,你所说的“reflection is used”是什么意思?什么是“reflection”? - AnV
14
反射是指通过Object.getClass()等方式在运行时检查对象、字段和方法的术语。 - FaultException
3
可序列化(Serializables)更适合于持久化数据,而另一方面,Parcelable对象则根本不应该持久化。这是一种非常糟糕的做法。 - TheAnimatrix
5
正如多人所述,Parcelable对象无法可靠地持久化,但Serializable对象可以(在一定程度内)。由于您的答案得分最高且给人留下了涵盖所有重要差异的印象,因此您应该提到这一点。 - LarsH
8
现在,Parcelable的实现速度与Serializable一样快,只需在Android Studio中按下ALT + INSERT键,对于任何实现Parcelable接口的类,IDE将会自动完成这个操作。 - Ali Nem
显示剩余9条评论

223

可序列化(Serializable)是Java标准接口。实现该接口可以将类标记为可序列化,Java会在某些情况下自动对其进行序列化。

可被包裹(Parcelable)是一个Android特有的接口,需要你手动实现序列化。它被创建出来是为了比Serializable更高效,并解决默认Java序列化方案的一些问题。

我相信Binder和AIDL使用的是Parcelable对象。

然而,在Intent中也可以使用Serializable对象。


1
如何序列化一个Parcelable对象?如何使其持久化? - Hades
@Haded 获取对象状态的内容并将其存储在文件或SQLLite数据库中。序列化对于在Android中的不同组件之间或完全不同的应用程序之间传输对象非常有用。 - Jono
7
这是一个很好的解释。我也注意到了这个: "Parcel不是通用的序列化机制。这个类(以及相应的Parcelable API,用于将任意对象放入Parcel中)被设计为高性能IPC传输。因此,将任何Parcel数据放入持久存储中是不合适的:对Parcel中任何数据的基础实现的更改可能会导致旧数据无法读取。" http://developer.android.com/reference/android/os/Parcel.html - Sam003
@Zhisheng 什么是任意对象?我们可以把哪些类型的对象放入包裹中? - hasnain_ahmad
使用Gson将对象转换为JSON字符串怎么样? - F.O.O

57
在Parcelable中,开发者编写自定义代码进行编组和解组,因此与序列化相比,它创建的垃圾对象更少。Parcelabale的性能大幅提高(约快两倍),因为采用了这种自定义实现方式。
Serializable是一个标记接口,这意味着用户无法根据自己的要求编组数据。在序列化中,使用Java反射API在Java虚拟机(JVM)上执行编组操作。这有助于识别Java对象的成员和行为,但也会创建许多垃圾对象。由于这个原因,与Parcelable相比,序列化过程较慢。
“编组”和“解组”的含义是什么?
简单来说,“编组”是将数据或对象转换为字节流的过程,“解组”则是将字节流转换回它们原始的数据或对象的逆过程。转换是通过“序列化”实现的。
参考链接:http://www.jguru.com/faq/view.jsp?EID=560072

4
很好的解释,即使没有冗长的例子也足够了。这正是我需要复习的东西。 - sud007

42

Parcelable是Android开发中的一种标准。但并不是因为它速度更快

Parcelable是数据传输的推荐方法。但是,如果您像这个存储库中展示的那样正确使用Serializable,您会发现Serializable有时甚至比Parcelable更快。或者至少计时是可比较的。

Parcelable比Serializable更快吗?

否,如果序列化得当。

通常情况下,在平均Android设备上(如果*正确完成),Java序列化写入约比Parcelable快3.6倍,读取约比Parcelable快1.6倍。此外,它证明了Java序列化(如果做得好)是一种快速存储机制,即使对于具有每个对象10个字段的相对大的对象图形11000个对象也可以给出可接受的结果。

* 顺便提一下,通常每个盲目地声称“Parcelable更快”的人将其与默认自动序列化进行比较,后者在内部使用了反射。这是不公平的比较,因为Parcelable使用手动(而且非常复杂)的过程将数据写入流中。通常没有提到的是,根据文档,标准的Java Serializable也可以使用writeObject()和readObject()方法手动完成。有关更多信息,请参见JavaDocs。这是为获得最佳性能而应该完成的方式。

那么,如果可序列化更快更容易实现,为什么Android还要使用Parcelable?

原因是本地代码。 Parcelable不仅适用于进程间通信,还可用于交互式编码。您可以从C++本地层发送和接收对象。就是这样。

该选择哪一个?两者都可以很好地工作。但我认为Parcelable是更好的选择,因为它被Google推荐,并且正如您从这个主题中看到的那样,更受欢迎。


1
你能引用一下你的来源吗?我会非常感激。谢谢! - Archie G. Quiñones
4
这个答案是我从一位在AOSP相关项目工作的经验丰富的开发人员 https://twitter.com/bwdude 那里得到的。他说,用于与SDK层通信的本地C++代码使用其自己的Parcelable实现。我猜他谈论的是这个类 https://android.googlesource.com/platform/frameworks/native/+/brillo-m10-dev/include/binder/Parcelable.h我知道这不是最好的解释,但目前这是我所能提供的最好的了。如果您找到其他信息,请务必在此发布 =) - Maksim Turaev
希望我能给你点赞不止一次。我见过很多优秀的Android和Java专家都选择了这里最受欢迎的答案。缺乏文档确实阻碍了Serializable的发展。感觉这是推广特定API的影响。谢谢! - Manish Kumar Sharma
你能解释一下什么是代码间通信吗? - linjiejun
1
我猜这是当你想在C++和Java之间进行通信时。不仅仅是在Java和Java之间。 - Maksim Turaev

42
如果你想成为一个好的开发者,花费额外的时间去实现Parcelable是值得的,因为它的性能比Serializable快10倍,且使用更少的资源。
然而,在大多数情况下,Serializable的速度缓慢不会被注意到。可以放心使用它,但请记住序列化是一项昂贵的操作,所以尽量减少使用。
如果你试图传递一个包含成千上万个序列化对象的列表,整个过程可能需要超过一秒钟的时间。这可能会使从纵向到横向的转换或旋转感觉非常缓慢。
来源: http://www.developerphil.com/parcelable-vs-serializable/

然而,在大多数情况下,Serializable 的缓慢不会引起注意。 - linjiejun

21

实际上,我将成为唯一支持 Serializable 的人。由于设备比几年前好得多,并且还存在其他更微妙的差异,速度差异不再那么显著。有关更多信息,请参见我在博客中发布的内容。


1
感谢分享。实现可序列化更简单,而且在那些罕见的超级优化情况下需要权衡决策。 - Ankan-Zerob
2
另一种观点,特别是当它有实验和结果支持时,非常有帮助。我必须处理大量现有的基于Parcelable的源代码,并且现在我已经阅读了您的博客文章,可能会对其中一些进行重构。 - Les

12

1. Serializable

@see http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html

是什么接口?

  • 是标准的Java接口

速度

  • 比Parcelable较慢

2. Parcelable

@see http://developer.android.com/reference/android/os/Parcelable.html

是什么接口?

  • 是Android OS(操作系统)的接口
    • 这意味着Google开发了Parcelable以在Android上提高性能

速度

  • 更快(因为它经过优化,适用于Android开发)

In Conclusion

请注意,Serializable是标准的Java接口,而Parcelable是用于Android开发的。


你也应该添加它们的用途。 - Anshul Tyagi

8

是的,你说得对。http://geeksforandroidgeeks.com/android/difference-between-parcelable-and-serializable/ - Vivek Samele

4

如果您在Android Studio中使用Parcelable插件,实现Parcelable可以更快。请搜索“Android Parcelable代码生成器”。


4

Serializable接口可以像Parcelable一样使用,这样可以获得(不多)更好的性能表现。只需覆盖这两个方法来处理手动编组和解组过程:

private void writeObject(java.io.ObjectOutputStream out)
    throws IOException
private void readObject(java.io.ObjectInputStream in)
    throws IOException, ClassNotFoundException

然而,我认为在开发本地Android应用时,使用Android API 是一个好方法。

参见:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接