Serialización Parcelable vs Serializable

Publicación por entregas

imagen.png

El proceso de transformar el estado de una instancia en una forma que se puede almacenar o transmitir.

ObjectOutputStreamObjectOutputStream

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;
    }
}
复制代码

método writeObject

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;
    }
}
复制代码

Llame al método writeObject0

  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());
            }
        }

    }
复制代码

Proceso de creación de ObjectStreamClass

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);
    }
}
复制代码

en el constructor ObjectStreamClass

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;
}
复制代码

Propiedades de lectura usando la reflexión

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

imagen.png

Kotlin tiene una anotación Parcelize que puede ayudarnos a generar el código que necesitamos escribir después de implementar Parcelable

  • El objeto implementa sus propios métodos de entrada y salida para evitar la reflexión sobre la estructura de clases.
  • Los flujos binarios se almacenan en memoria contigua con una huella más pequeña
  • Sacrifique la facilidad de uso (que se puede compensar con Parcelize) por un rendimiento extremo

Serializable

  • Use la reflexión para obtener la estructura de clases y la información de atributos, y se generará información intermedia en el proceso
  • Hay una estructura de caché, en el caso de analizar el mismo tipo, el caché se puede reutilizar
  • El rendimiento está dentro del rango aceptable y la facilidad de uso es relativamente buena

Escenario de paso por valor de intención

En el writeSerializable en la clase Parcel.java

Serializable es convertir primero el objeto en ByteArray a través de ObjectOutputStream y luego escribir en Parcel a través de 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 llama a la lógica en el método writeToParcel implementado dentro del objeto y escribe directamente en Parcel a través de algunos métodos de escritura.

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);
        }
    }
}
复制代码

Debido al mecanismo de almacenamiento en caché de ObjectStreamClass, en un proceso de serialización, si está involucrada una gran cantidad de instancias diferentes de la misma clase, el rendimiento de Serializable tendrá una ventaja.

Supongo que te gusta

Origin juejin.im/post/7085307179896406030
Recomendado
Clasificación