🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] Android中对于对象有两种方式可以实现序列化,分别为实现Serializable接口和实现Parcelable接口。 # Serializable接口 使用Serializable接口实现序列化时,只要让类实现Serializable接口并声明一个serialVersionUID即可。 ```java public class Book implements Serializable { private static final long serialVersionUID = 5474576373476457684L; private String mName; private float mPrice; public String getName() { return mName; } public void setName(String name) { mName = name; } public float getPrice() { return mPrice; } public void setPrice(float price) { mPrice = price; } } ``` # Parcelable接口 Parcelable接口声明如下: ```java public interface Parcelable { public @ContentsFlags int describeContents(); // 对象写入Parcel public void writeToParcel(Parcel dest, @WriteFlags int flags); public interface Creator<T> { // 从Parcel中恢复对象 public T createFromParcel(Parcel source); // 创建一个对象数组 public T[] newArray(int size); } // 支持传入ClassLoader public interface ClassLoaderCreator<T> extends Creator<T> { public T createFromParcel(Parcel source, ClassLoader loader); } } ``` 实现类示例如下: ```java public class Book implements Parcelable { private String mName; private String mAuthor; private float mPrice; protected Book(Parcel in) { mName = in.readString(); mAuthor = in.readString(); mPrice = in.readFloat(); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mName); dest.writeString(mAuthor); dest.writeFloat(mPrice); } } ``` 需要注意的一点是,写入对象到Parcel和从Parcel读取对象两个方法中,成员变量的顺序需要一致,否则将会产生异常。 # 对比 在实际开发中,推荐使用Parcelable接口: 1、Serializable使用简单但是开销大,序列化和反序列化过程需要大量的IO操作,使用了反射机制,过程相对缓慢,且产生很多临时对象需要频繁垃圾回收 2、Parcelable使用稍微麻烦,但是效率高 3、Parcelable推荐用在内存序列化上;Serializable推荐用在将对象序列化到存储设备中或对象序列化后通过网络传输。 # Parcelable源码分析 ## 序列化 我们使用Intent传递对象是最常见的使用Parcelable序列化使用场景,下面我们来看看序列化后的对象到底是怎么传递的。 ```java public @NonNull Intent putExtra(String name, Parcelable value) { if (mExtras == null) { mExtras = new Bundle(); } mExtras.putParcelable(name, value); return this; } ``` 上面是Intent的putExtra方法,我们在传递数据时将Parcelable序列化后的对象作为参数传入。可以看到Parcelable对象被存放到mExtras,也就是一个Bundle对象中。看看Bundle的putParcelable方法: ```java ArrayMap<String, Object> mMap = null; public void putParcelable(@Nullable String key, @Nullable Parcelable value) { //... mMap.put(key, value); } ``` 可以看到,序列化后的对象被直接存到了Bundle的一个Map集合中了。由于Bundle也实现了Parcelable接口,在传递数据时,Bundle也是会被传递过去的,会调用其writeToParcel方法: ```java // 将Bundle中的内容写入到Parcel对象中 public void writeToParcel(Parcel parcel, int flags) { //... super.writeToParcelInner(parcel, flags); } void writeToParcelInner(Parcel parcel, int flags) { //... // 此处直接将Bundle的整个mMap传入 parcel.writeArrayMapInternal(map); } ``` 来看看Parcel对象拿到Map后的操作: ```java void writeArrayMapInternal(ArrayMap<String, Object> val) { //... // 将map中的每一个对象依次写入Parcel中 for (int i=0; i<N; i++) { writeString(val.keyAt(i)); writeValue(val.valueAt(i)); } } public final void writeValue(Object v) { if (v instanceof String) { writeInt(VAL_STRING); writeString((String) v); } else if (v instanceof Integer) { writeInt(VAL_INTEGER); writeInt((Integer) v); } else if (v instanceof Parcelable) { writeInt(VAL_PARCELABLE); writeParcelable((Parcelable) v, 0); } //... } public final void writeParcelable(Parcelable p, int parcelableFlags) { //... writeParcelableCreator(p); //调用序列化后的Parcelable对象的writeToParcel方法 p.writeToParcel(this, parcelableFlags); } ``` 可以看到,最终调用了我们实现序列化对象的writeToParcel方法。 ## 反序列化 接下来看看从Parcel中恢复Bundle对象: ```java public void readFromParcel(Parcel parcel) { super.readFromParcelInner(parcel); mFlags = FLAG_ALLOW_FDS; maybePrefillHasFds(); } void readFromParcelInner(Parcel parcel) { int length = parcel.readInt(); readFromParcelInner(parcel, length); } ``` 接下来看看readFromParcelInner方法: ```java private void readFromParcelInner(Parcel parcel, int length) { //... Parcel p = Parcel.obtain(); p.setDataPosition(0); p.appendFrom(parcel, offset, length); p.adoptClassCookies(parcel); p.setDataPosition(0); mParcelledData = p; } ``` 可以看到,为mParcelledData进行赋值。然后这条线就断了,那么我们就从Bundle中获取传递过来的Parcelable对象看看: ```java public <T extends Parcelable> T getParcelable(@Nullable String key) { unparcel(); Object o = mMap.get(key); //... return (T) o; } ``` 首先调用unparcel方法,然后根据key从map中获取Parcelable对象。来看看unparcel方法: ```java void unparcel() { final Parcel source = mParcelledData; if (source != null) { // 这个source就是我们前面拿到的Parcel对象 initializeFromParcelLocked(source, /*recycleParcel=*/ true); } //... } ``` 看看initializeFromParcelLocked方法: ```java private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel) { ArrayMap<String, Object> map = mMap; //... try { parcelledData.readArrayMapInternal(map, count, mClassLoader); } catch (BadParcelableException e) { //... } finally { mMap = map; if (recycleParcel) { recycleParcel(parcelledData); } mParcelledData = null; } } ``` 最终调用了parcelledData的readArrayMapInternal方法: ```java void readArrayMapInternal(ArrayMap outVal, int N, ClassLoader loader) { int startPos; // 依次取出每一个属性,并存入map while (N > 0) { String key = readString(); Object value = readValue(loader); outVal.append(key, value); N--; } outVal.validate(); } ``` 读取属性的readValue方法源码如下: ```java public final Object readValue(ClassLoader loader) { int type = readInt(); switch (type) { case VAL_STRING: return readString(); case VAL_INTEGER: return readInt(); case VAL_PARCELABLE: return readParcelable(loader); //... } } public final <T extends Parcelable> T readParcelable(ClassLoader loader) { // 获取Creator Parcelable.Creator<?> creator = readParcelableCreator(loader); //... return (T) creator.createFromParcel(this); } ``` 最终调用Creator的createFromParcel方法,也就是我们自己序列化对象写的那个createFromParcel方法。其中获取Creator代码如下: ```java public final Parcelable.Creator<?> readParcelableCreator(ClassLoader loader) { String name = readString(); Parcelable.Creator<?> creator; synchronized (mCreators) { HashMap<String,Parcelable.Creator<?>> map = mCreators.get(loader); if (map == null) { map = new HashMap<>(); mCreators.put(loader, map); } creator = map.get(name); if (creator == null) { try { // If loader == null, explicitly emulate Class.forName(String) "caller // classloader" behavior. ClassLoader parcelableClassLoader = (loader == null ? getClass().getClassLoader() : loader); // Avoid initializing the Parcelable class until we know it implements // Parcelable and has the necessary CREATOR field. http://b/1171613. Class<?> parcelableClass = Class.forName(name, false /* initialize */, parcelableClassLoader); if (!Parcelable.class.isAssignableFrom(parcelableClass)) { throw new BadParcelableException("Parcelable protocol requires that the " + "class implements Parcelable"); } Field f = parcelableClass.getField("CREATOR"); if ((f.getModifiers() & Modifier.STATIC) == 0) { throw new BadParcelableException("Parcelable protocol requires " + "the CREATOR object to be static on class " + name); } Class<?> creatorType = f.getType(); if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) { // Fail before calling Field.get(), not after, to avoid initializing // parcelableClass unnecessarily. throw new BadParcelableException("Parcelable protocol requires a " + "Parcelable.Creator object called " + "CREATOR on class " + name); } creator = (Parcelable.Creator<?>) f.get(null); } map.put(name, creator); } } return creator; } ``` 可以看到,通过反射拿到Creator。