Parcelable vs Serializable Serialization

Serialization

image.png

The process of transforming the state of an instance into a form that can be stored or transmitted.

ObjectOutputStream

Constructor

public ObjectOutputStream(OutputStream out) throws IOException {
    verifySubclass();
    bout = new BlockDataOutputStream(out);//用于写入文件的Stream
    handles = new HandleTable(10, (float) 3.00);
    subs = new ReplaceTable(10, (float) 3.00);
    enableOverride = false;
    writeStreamHeader(); //开始写入魔数和版本号
    bout.setBlockDataMode(true);
    if (extendedDebugInfo) {
        debugInfoStack = new DebugTraceInfoStack();
    } else {
        debugInfoStack = null;
    }
}
复制代码

writeObject method

public final void writeObject(Object obj) throws IOException {
    if (enableOverride) {
        writeObjectOverride(obj);
        return;
    }
    try {
        writeObject0(obj, false);
    } catch (IOException ex) {
        if (depth == 0) {
            try {
                writeFatalException(ex);

            } catch (IOException ex2) {
            }
        }
        throw ex;
    }
}
复制代码

Call the writeObject0 method

  private void writeObject0(Object obj, boolean unshared)
        throws IOException
    {
           。。。
           //创建出来一个原始数据的描述信息的实例
          desc = ObjectStreamClass.lookup(cl, true);
           。。。
         //根据类型信息将实例信息写入输出流
        if (obj instanceof Class) {
            writeClass((Class) obj, unshared);
        } else if (obj instanceof ObjectStreamClass) {
            writeClassDesc((ObjectStreamClass) obj, unshared);
        // END Android-changed: Make Class and ObjectStreamClass replaceable.
        } else if (obj instanceof String) {
            writeString((String) obj, unshared);
        } else if (cl.isArray()) {
            writeArray(obj, desc, unshared);
        } else if (obj instanceof Enum) {
            writeEnum((Enum<?>) obj, desc, unshared);
        } else if (obj instanceof Serializable) {
            writeOrdinaryObject(obj, desc, unshared);
        } else {
            if (extendedDebugInfo) {
                throw new NotSerializableException(
                    cl.getName() + "\n" + debugInfoStack.toString());
            } else {
                throw new NotSerializableException(cl.getName());
            }
        }

    }
复制代码

ObjectStreamClass creation process

static ObjectStreamClass lookup(Class<?> cl, boolean all) {
    ...
    Reference<?> ref = Caches.localDescs.get(key);//读取缓存
    Object entry = null;
    if (ref != null) {
        entry = ref.get();
    }
    EntryFuture future = null;
    if (entry == null) {
        EntryFuture newEntry = new EntryFuture();
        Reference<?> newRef = new SoftReference<>(newEntry);
        do {
            if (ref != null) {
                Caches.localDescs.remove(key, ref);
            }
            ref = Caches.localDescs.putIfAbsent(key, newRef);
            if (ref != null) {
                entry = ref.get();
            }
        } while (ref != null && entry == null);
        if (entry == null) {
            future = newEntry;
        }
    }

    if (entry instanceof ObjectStreamClass) {  // check common case first
        return (ObjectStreamClass) entry;
    }
    if (entry instanceof EntryFuture) {
        future = (EntryFuture) entry;
        if (future.getOwner() == Thread.currentThread()) {
            entry = null;
        } else {
            entry = future.get();
        }
    }
    //没有缓存的情况
    if (entry == null) {
        try {
            entry = new ObjectStreamClass(cl);
        } catch (Throwable th) {
            entry = th;
        }
        if (future.set(entry)) {
            Caches.localDescs.put(key, new SoftReference<Object>(entry));
        } else {
            entry = future.get();
        }
    }

    if (entry instanceof ObjectStreamClass) {
        return (ObjectStreamClass) entry;
    } else if (entry instanceof RuntimeException) {
        throw (RuntimeException) entry;
    } else if (entry instanceof Error) {
        throw (Error) entry;
    } else {
        throw new InternalError("unexpected entry: " + entry);
    }
}
复制代码

into the ObjectStreamClass constructor

private ObjectStreamClass(final Class<?> cl) {
    this.cl = cl;
    ...
    name = cl.getName();//反射获取
    isProxy = Proxy.isProxyClass(cl);
    isEnum = Enum.class.isAssignableFrom(cl);
    serializable = Serializable.class.isAssignableFrom(cl);
    externalizable = Externalizable.class.isAssignableFrom(cl);

    Class<?> superCl = cl.getSuperclass();
    superDesc = (superCl != null) ? lookup(superCl, false) : null;
    ...
    suid = getDeclaredSUID(cl);
    fields = getSerialFields(cl);
    computeFieldOffsets();
    initialized = true;
}
复制代码

Reading properties using reflection

private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
    Field[] clFields = cl.getDeclaredFields();
    ArrayList<ObjectStreamField> list = new ArrayList<>();
    int mask = Modifier.STATIC | Modifier.TRANSIENT;

    for (int i = 0; i < clFields.length; i++) {
        if ((clFields[i].getModifiers() & mask) == 0) {
            list.add(new ObjectStreamField(clFields[i], false, true));
        }
    }
    int size = list.size();
    return (size == 0) ? NO_FIELDS :
        list.toArray(new ObjectStreamField[size]);
}
复制代码

Parcelable

image.png

Kotlin has a Parcelize annotation that can help us generate the code we need to write after implementing Parcelable

  • The object implements its own entry and exit methods to avoid reflection on the class structure
  • Binary streams are stored in contiguous memory with a smaller footprint
  • Sacrifice ease of use (which can be made up for with Parcelize) for extreme performance

Serializable

  • Use reflection to obtain class structure and attribute information, and intermediate information will be generated in the process
  • There is a cache structure, in the case of parsing the same type, the cache can be reused
  • The performance is within the acceptable range, and the ease of use is relatively good

Intent pass-by-value scenario

Into the writeSerializable in the Parcel.java class

Serializable is to first convert the object into ByteArray through ObjectOutputStream, and then write to Parcel through writeByteArray

public final void writeSerializable(@Nullable Serializable s) {
    if (s == null) {
        writeString(null);
        return;
    }
    String name = s.getClass().getName();
    writeString(name);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(s);
        oos.close();

        writeByteArray(baos.toByteArray());
    } catch (IOException ioe) {
        throw new RuntimeException("Parcelable encountered " +
            "IOException writing serializable object (name = " + name +
            ")", ioe);
    }
}
复制代码

Parcelable calls the logic in the writeToParcel method implemented inside the object, and writes directly to Parcel through some write methods

public static void writeToParcel(@Nullable CharSequence cs, @NonNull Parcel p,
        int parcelableFlags) {
    if (cs instanceof Spanned) {
        p.writeInt(0);
        p.writeString8(cs.toString());

        Spanned sp = (Spanned) cs;
        Object[] os = sp.getSpans(0, cs.length(), Object.class);

        for (int i = 0; i < os.length; i++) {
            Object o = os[i];
            Object prop = os[i];

            if (prop instanceof CharacterStyle) {
                prop = ((CharacterStyle) prop).getUnderlying();
            }

            if (prop instanceof ParcelableSpan) {
                final ParcelableSpan ps = (ParcelableSpan) prop;
                final int spanTypeId = ps.getSpanTypeIdInternal();
                if (spanTypeId < FIRST_SPAN || spanTypeId > LAST_SPAN) {
                    Log.e(TAG, "External class "" + ps.getClass().getSimpleName()
                            + "" is attempting to use the frameworks-only ParcelableSpan"
                            + " interface");
                } else {
                    p.writeInt(spanTypeId);
                    ps.writeToParcelInternal(p, parcelableFlags);
                    writeWhere(p, sp, o);
                }
            }
        }

        p.writeInt(0);
    } else {
        p.writeInt(1);
        if (cs != null) {
            p.writeString8(cs.toString());
        } else {
            p.writeString8(null);
        }
    }
}
复制代码

Due to the caching mechanism of ObjectStreamClass, in a serialization process, if a large number of different instantiations of the same class are involved, the performance of Serializable will have an advantage.

Guess you like

Origin juejin.im/post/7085307179896406030