深入c++层分析Serializable和Parcelable的区别

深入c++层分析Serializable和Parcelable的区别

一、Serializable的源码分析

Serializable是为了保存对象的属性到本地文件、网络传输等方便数据传输,由于对应使用了ObjectInputStream和ObjectOutputStream进行读写,所以在读取过程中会使用了反射以及产生过多的临时变量。

由于Serializable的性能过低,不太适用于性能资源相对紧张的嵌入式设备应用间传递数据,所以Android设计了新序列化方式–Parcelable用于内存间传递数据

接下来我们从ObjectOutputStream读取数据来分析为什么消耗过多资源

1、首先来看一下ObjectOutputStream产生的中间变量

public class ObjectOutputStream
    extends OutputStream implements ObjectOutput, ObjectStreamConstants
{

    private static class Caches {
        /** 子类安全性审核结果的缓存 */
        static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
            new ConcurrentHashMap<>();

        /** 将WeakReferences引用到审核的子类中 */
        static final ReferenceQueue<Class<?>> subclassAuditsQueue =
            new ReferenceQueue<>();
    }

    /** 用于处理块数据转换的过滤流,是ObjectOutputStream的内部类,实际将数据写入的类 */
    private final BlockDataOutputStream bout;
    /** 后面会构造一个大小为10,负载因子为3的HandleTable和ReplaceTable */
    private final HandleTable handles;
    private final ReplaceTable subs;

    /** 流的协议版本 */
    private int protocol = PROTOCOL_VERSION_2;
    /** 递归深度 */
    private int depth;

    /** 用于写入基本类型字段值的缓冲区 */
    private byte[] primVals;

    /** 如果true,子类重写writeObjectOverride()处理,否则writeObject()处理   */
    private final boolean enableOverride;
    /** 如果true,调用replaceObject() */
    private boolean enableReplace;

    // 下面的值只在上行调用writeObject()/writeExternal()时有效
    /**
     * 上行调用类定义的writeObject方法时的上下文,持有当前被序列化的对象和当前对象描述符。在非 writeObject上行调用时为null
     */
    private SerialCallbackContext curContext;
    /** 当前PutField对象 */
    private PutFieldImpl curPut;

    /** 常规存储用于debug栈信息 */
    private final DebugTraceInfoStack debugInfoStack;

    …………
}

上面只是一些成员变量,还不包含局部变量就已经产生了变量来缓存数据,如果序列化对象的层级和深度加深,好用的资源可想而知,下面将会挑选重点来阐述序列化的过程

2、序列化过程

(1)有多个构造函数,这里选取一个public来分析
public ObjectOutputStream(OutputStream out) throws IOException {
        //验证子类是否违反安全约束
        verifySubclass();
        //构造一个BlockDataOutputStream用于向out写入序列化数据,实际写入的类对象
        bout = new BlockDataOutputStream(out);
        //构造一个大小为10,负载因子为3的HandleTable
        handles = new HandleTable(10, (float) 3.00);
        //构造一个大小为10,负载因子为3的ReplaceTable
        subs = new ReplaceTable(10, (float) 3.00);
        //恒为false,除非子类调用protected构造方法
        enableOverride = false;
        //向流的头里写入魔数和版本号
        writeStreamHeader();
        //将缓存模式打开,写入数据时先写入缓冲区
        bout.setBlockDataMode(true);
        //是否开启debug信息栈
        if (extendedDebugInfo) {
            debugInfoStack = new DebugTraceInfoStack();
        } else {
            debugInfoStack = null;
        }
    }
(2)verifySubclass方法
private void verifySubclass() {
        Class<?> cl = getClass();
        //如果是当前类,直接返回
        if (cl == ObjectOutputStream.class) {
            return;
        }
        //获取安全管理器是否有对应的权限,没有则返回
        SecurityManager sm = System.getSecurityManager();
        if (sm == null) {
            return;
        }
        //从弱引用队列中出队所有类,并移除缓存中相同的类
        processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
        //将ObjectOutputStream的子类存入Caches类的对象中
        WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
        Boolean result = Caches.subclassAudits.get(key);
        if (result == null) {
            //检查这个子类是否安全
            result = Boolean.valueOf(auditSubclass(cl));
            //将结果存储到缓存
            Caches.subclassAudits.putIfAbsent(key, result);
        }
        if (result.booleanValue()) {
            return;
        }
        //验证是否有实现权限,  如果没有权限则抛出SecurityException异常
        sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
    }

(3)再来看writeStreamHeader方法,写入了哪些头信息
protected void writeStreamHeader() throws IOException {
    bout.writeShort(STREAM_MAGIC); //写入两个字节:0xAC和0xED
    bout.writeShort(STREAM_VERSION); //写入两个字节:0x00和0x05
}

(4)通常我们构造了ObjectOutputStream oos = new ObjectOutputStream(out)后,会调用writeObject(Object)来写入对象

public final void writeObject(Object obj) throws IOException {
        //是否子类重写了,如果重写,交由子类的writeObjectOverride处理
        if (enableOverride) {
            writeObjectOverride(obj);
            return;
        }
        try {
            //写入对象
            writeObject0(obj, false);
        } catch (IOException ex) {
            if (depth == 0) {
                //安卓实现中使用try-catch忽略了次要的一些异常
                try {
                    writeFatalException(ex);
                } catch (IOException ex2) {
                    
                }
            }
            throw ex;
        }
    }


/**
  * 基础writeObject / writeUnshared实现。
  **/
private void writeObject0(Object obj, boolean unshared)
        throws IOException
    {
        //关闭缓存模式
        boolean oldMode = bout.setBlockDataMode(false);
        depth++;
        try {
            // 处理以前写过的和不可替换的对象
            int h;
            if ((obj = subs.lookup(obj)) == null) {
                writeNull();
                return;
            } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                writeHandle(h);
                return;
            // 安卓改变 start: 使Class和ObjectStreamClass可替换
            /*
            } else if (obj instanceof Class) {
                writeClass((Class) obj, unshared);
                return;
            } else if (obj instanceof ObjectStreamClass) {
                writeClassDesc((ObjectStreamClass) obj, unshared);
                return;
            */
            // 安卓改变 end: 使Class和ObjectStreamClass可替换
            }

            //检查可替换的对象
            Object orig = obj;
            Class<?> cl = obj.getClass();
            //序列化对象对应的Class对象的详细信息
            ObjectStreamClass desc;

            // BEGIN 安卓改变: 仅调用一次writeReplace,在java中for循环中判断始终为true,不需要循环
            /*
            for (;;) {
                // REMIND: 对于strings/arrays跳过检查?
                Class<?> repCl;
                desc = ObjectStreamClass.lookup(cl, true);
                if (!desc.hasWriteReplaceMethod() ||
                    (obj = desc.invokeWriteReplace(obj)) == null ||
                    (repCl = obj.getClass()) == cl)
                {
                    break;
                }
                cl = repCl;
                desc = ObjectStreamClass.lookup(cl, true);
                break;
            }
            */
            // 只替换一次通过

            Class repCl;
            //获取序列化对象对应的Class对象详细信息
            desc = ObjectStreamClass.lookup(cl, true);
            if (desc.hasWriteReplaceMethod() &&
                (obj = desc.invokeWriteReplace(obj)) != null &&
                (repCl = obj.getClass()) != cl)
            {
                cl = repCl;
                desc = ObjectStreamClass.lookup(cl, true);
            }
            // END 安卓改变: 仅调用一次writeReplace,在java中for循环中判断始终为true,不需要循环

            if (enableReplace) {
                //replaceObject用来替换这个对象进行序列化,默认实现为空,一般用于子类重写实现序列化的定制
                Object rep = replaceObject(obj);
                //如果对象被替换了
                if (rep != obj && rep != null) {
                    cl = rep.getClass();
                    //重新查找对应的ObjectStreamClass
                    desc = ObjectStreamClass.lookup(cl, true);
                }
                obj = rep;
            }

            // 如果对象被替换,则再次运行原始检查
            if (obj != orig) {
                subs.assign(orig, obj);
                if (obj == null) {
                    writeNull();
                    return;
                } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                    writeHandle(h);
                    return;
                // BEGIN 安卓改变:使Class和ObjectStreamClass可替换
                /*
                } else if (obj instanceof Class) {
                    writeClass((Class) obj, unshared);
                    return;
                } else if (obj instanceof ObjectStreamClass) {
                    writeClassDesc((ObjectStreamClass) obj, unshared);
                    return;
                */
                // END 安卓改变:使Class和ObjectStreamClass可替换
                }
            }

            // remaining cases
            // BEGIN 安卓改变: 使Class和ObjectStreamClass可替换
            if (obj instanceof Class) {
                writeClass((Class) obj, unshared);
            } else if (obj instanceof ObjectStreamClass) {
                writeClassDesc((ObjectStreamClass) obj, unshared);
            // END 安卓改变: 使Class和ObjectStreamClass可替换.
            //序列化对象类型为String、数组、枚举时,调用定制的写入方法
            } 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);
            //一般对象类型的写入,这里就是需要实现Serializable的对象写入的地方
            } 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());
                }
            }
        } finally {
            //结束方法前将方法栈深减去1
            depth--;
            //切换回之前的缓存模式
            bout.setBlockDataMode(oldMode);
        }
    }

(5)writeOrdinaryObject
/**
  * 最终会以一种递归的形式写入对象信息。
  **/
private void writeOrdinaryObject(Object obj, ObjectStreamClass desc,
         boolean unshared) throws IOException {
    if (extendedDebugInfo)
        debugInfoStack.push(
                (depth == 1 ? "root " : "") + "object (class \"" +
                obj.getClass().getName() + "\", " + obj.toString() + ")");
    try {
        //检查ObjectStreamClass对象
        desc.checkSerialize();
        //写入字节0x73
        bout.writeByte(TC_OBJECT);
        //写入对应的Class对象的信息
        writeClassDesc(desc, false);
        handles.assign(unshared ? null : obj);//如果是share模式把这个对象加入缓存
        if (desc.isExternalizable() && !desc.isProxy()) {
            writeExternalData((Externalizable) obj);
        } else {
            //写入这个对象变量信息及其父类的成员变量
            //将这个实例及其父类基本数据类型写入文件,如果检测到有引用类型,那么会继续调用
            writeSerialData(obj, desc);
        }
    } finally {
        if (extendedDebugInfo) {
            debugInfoStack.pop();
        }
    }
}

(6)写入描述信息
    /**
     * 将给定类描述符的表示形式写入流。
     */
    private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
        throws IOException
    {
        int handle;
        if (desc == null) {
            //描述为空,写null
            writeNull();
        } else if (!unshared && (handle = handles.lookup(desc)) != -1) {
            //共享模式且缓存中已有该类描述符时,写对应句柄值
            writeHandle(handle);
        } else if (desc.isProxy()) {
            //描述信息为动态代理类写入
            writeProxyDesc(desc, unshared);
        } else {
            //标准类写入
            writeNonProxyDesc(desc, unshared);
        }
    }

    private boolean isCustomSubclass() {
        // 如果此类是ObjectOutputStream的自定义子类,则返回true
        return getClass().getClassLoader()
                   != ObjectOutputStream.class.getClassLoader();
    }

    /**
     * 将表示动态代理类的类描述符写入流中。
     */
    private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
        throws IOException
    {
        bout.writeByte(TC_PROXYCLASSDESC);
        //共享则写入缓存
        handles.assign(unshared ? null : desc);
        //获取类实现的接口,然后写入接口个数和接口名。此处使用反射
        Class<?> cl = desc.forClass();
        Class<?>[] ifaces = cl.getInterfaces();
        bout.writeInt(ifaces.length);
        //写入接口名
        for (int i = 0; i < ifaces.length; i++) {
            bout.writeUTF(ifaces[i].getName());
        }
        //打开缓存模式
        bout.setBlockDataMode(true);
        //如果是子类,校验包权限。此处使用反射
        if (cl != null && isCustomSubclass()) {
            ReflectUtil.checkPackageAccess(cl);
        }
        //装配动态代理类,子类可以重写这个方法存储类信息到流中,默认什么也不做
        annotateProxyClass(cl);
        //关闭缓存模式
        bout.setBlockDataMode(false);
        //写入块结束符
        bout.writeByte(TC_ENDBLOCKDATA);
        //接下来再递归写入父类信息
        writeClassDesc(desc.getSuperDesc(), false);
    }

    /**
     * 将代表标准(即不是动态代理)类的类描述符写入流中。
     */
    private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
        throws IOException
    {
        bout.writeByte(TC_CLASSDESC);
        handles.assign(unshared ? null : desc);

        if (protocol == PROTOCOL_VERSION_1) {
            // 不要使用旧协议调用类描述符写钩子
            desc.writeNonProxy(this);
        } else {
            writeClassDescriptor(desc);
        }

        Class<?> cl = desc.forClass();
        bout.setBlockDataMode(true);
        if (cl != null && isCustomSubclass()) {
            ReflectUtil.checkPackageAccess(cl);
        }
        //子类可以重写这个方法存储类信息到流中,默认什么也不做
        annotateClass(cl);
        bout.setBlockDataMode(false);
        bout.writeByte(TC_ENDBLOCKDATA);
        //接下来再递归写入父类信息
        writeClassDesc(desc.getSuperDesc(), false);
    }

(8)写入字段信息
    /**
     * 通过调用其writeExternal()方法来写入给定对象的可外部化数据。
     */
    private void writeExternalData(Externalizable obj) throws IOException {
        PutFieldImpl oldPut = curPut;
        curPut = null;

        if (extendedDebugInfo) {
            debugInfoStack.push("writeExternal data");
        }
        //存储上下文
        SerialCallbackContext oldContext = curContext;
        try {
            curContext = null;
            if (protocol == PROTOCOL_VERSION_1) {
                //协议版本1
                obj.writeExternal(this);
            } else {
                //默认协议是2,所以会使用块输出流
                bout.setBlockDataMode(true);
                //取决于类的实现
                obj.writeExternal(this);
                bout.setBlockDataMode(false);
                //写入块数据结束符
                bout.writeByte(TC_ENDBLOCKDATA);
            }
        } finally {
            //将上下文改变回来
            curContext = oldContext;
            if (extendedDebugInfo) {
                debugInfoStack.pop();
            }
        }

        curPut = oldPut;
    }

    /**
     * 为给定对象的每个可序列化类(从超类到子类)写入实例数据。
     */
    private void writeSerialData(Object obj, ObjectStreamClass desc)
        throws IOException
    {
        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
        for (int i = 0; i < slots.length; i++) {
            ObjectStreamClass slotDesc = slots[i].desc;
            //重写了writeObject方法
            if (slotDesc.hasWriteObjectMethod()) {
                PutFieldImpl oldPut = curPut;
                curPut = null;
                SerialCallbackContext oldContext = curContext;

                if (extendedDebugInfo) {
                    debugInfoStack.push(
                        "custom writeObject data (class \"" +
                        slotDesc.getName() + "\")");
                }
                try {
                    curContext = new SerialCallbackContext(obj, slotDesc);
                    bout.setBlockDataMode(true);
                    slotDesc.invokeWriteObject(obj, this);
                    bout.setBlockDataMode(false);
                    bout.writeByte(TC_ENDBLOCKDATA);
                } finally {
                    curContext.setUsed();
                    curContext = oldContext;
                    if (extendedDebugInfo) {
                        debugInfoStack.pop();
                    }
                }

                curPut = oldPut;
            } else {
                //如果没有重写writeObject则输出默认内容
                defaultWriteFields(obj, slotDesc);
            }
        }
    }

    /**
     * 获取并写入给定对象的可序列化字段的值以流式传输。 给定的类描述符指定要写入的字段值,以及应按什么顺序写入它们。
     */
    private void defaultWriteFields(Object obj, ObjectStreamClass desc)
        throws IOException
    {
        Class<?> cl = desc.forClass();
        if (cl != null && obj != null && !cl.isInstance(obj)) {
            throw new ClassCastException();
        }

        desc.checkDefaultSerialize();

        int primDataSize = desc.getPrimDataSize();
        if (primVals == null || primVals.length < primDataSize) {
            primVals = new byte[primDataSize];
        }
        //将基本类型数据的字段值存入缓冲区
        desc.getPrimFieldValues(obj, primVals);
        //输出缓冲区内容
        bout.write(primVals, 0, primDataSize, false);

        ObjectStreamField[] fields = desc.getFields(false);
        //获取非基本数据类型对象
        Object[] objVals = new Object[desc.getNumObjFields()];
        int numPrimFields = fields.length - objVals.length;
        desc.getObjFieldValues(obj, objVals);
        for (int i = 0; i < objVals.length; i++) {
            if (extendedDebugInfo) {
                debugInfoStack.push(
                    "field (class \"" + desc.getName() + "\", name: \"" +
                    fields[numPrimFields + i].getName() + "\", type: \"" +
                    fields[numPrimFields + i].getType() + "\")");
            }
            try {
                //递归继续写入
                writeObject0(objVals[i],
                             fields[numPrimFields + i].isUnshared());
            } finally {
                if (extendedDebugInfo) {
                    debugInfoStack.pop();
                }
            }
        }
    }
(9)举几个基础类型写入
    private void writeString(String str, boolean unshared) throws IOException {
        handles.assign(unshared ? null : str);
        //获得UTF编码长度
        long utflen = bout.getUTFLength(str);
        if (utflen <= 0xFFFF) {
            //写入类型标志符
            bout.writeByte(TC_STRING);
            //写入utf编码数据
            bout.writeUTF(str, utflen);
        } else {
            //写入类型标志符
            bout.writeByte(TC_LONGSTRING);
            //写入utf编码数据
            bout.writeLongUTF(str, utflen);
        }
    }

    private void writeEnum(Enum<?> en,
                           ObjectStreamClass desc,
                           boolean unshared)
        throws IOException
    {   
        //写入类型标志符
        bout.writeByte(TC_ENUM);
        ObjectStreamClass sdesc = desc.getSuperDesc();
        //写入类信息
        writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);
        //共享模式写入缓存
        handles.assign(unshared ? null : en);
        //以字符串形式写入name
        writeString(en.name(), false);
    }

(10)BlockDataOutputStream类,在这里我就不分析了,喜欢深入了解的朋友,可以继续查看BlockDataOutputStream的相关write*方法


一.Parcelable的源码分析

Parcelable在性能消耗和内存开销上都比Serializable要小,所以内存间传递数据推荐使用Parcelable。Parcelable不适用于磁盘上存储数据,由于Parcelable存储数据是有序的,在磁盘上持久化数据,会随着对象的不同版本,新增、删除、交换位置等原因,导致读取数据异常。

1、编码实现形式

(1)编写一个实体类

public class Bean1 implements Parcelable {
    private String name;
    private int age;

    protected Bean1(Parcel in) {
        //从Parcel对象读取反序列化值,必须和写入保持一致
        name = in.readString();
        age = in.readInt();
    }


    public static final Creator<Bean1> CREATOR = new Creator<Bean1>() {
        @Override
        public Bean1 createFromParcel(Parcel in) {
            return new Bean1(in);
        }

        @Override
        public Bean1[] newArray(int size) {
            return new Bean1[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;//默认为0,如果需要序列化file description,改为1
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        //向Parcel对象写入数据用于本地化--必须和读取一致
        dest.writeString(name);
        dest.writeInt(age);
    }
}

2.从编写aidl看Parcelable序列化过程

(1)编写aidl
// IBean.aidl
package com.yetao.android.library.sdk28;

// Declare any non-default types here with import statements

interface IBean {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

package com.yetao.android.library.sdk28;
// 在这里使用import语句声明所有非默认类型

//android studio自动生成
public interface IBean extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.yetao.android.library.sdk28.IBean {
        private static final java.lang.String DESCRIPTOR = "com.yetao.android.library.sdk28.IBean";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.yetao.android.library.sdk28.IBean interface,
         * generating a proxy if needed.
         */
        public static com.yetao.android.library.sdk28.IBean asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.yetao.android.library.sdk28.IBean))) {
                return ((com.yetao.android.library.sdk28.IBean) iin);
            }
            return new com.yetao.android.library.sdk28.IBean.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;

            //按顺序从data中读出字段值,必须按顺序写
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_basicTypes: {
                    data.enforceInterface(descriptor);
                    int _arg0;
                    _arg0 = data.readInt();
                    long _arg1;
                    _arg1 = data.readLong();
                    boolean _arg2;
                    _arg2 = (0 != data.readInt());
                    float _arg3;
                    _arg3 = data.readFloat();
                    double _arg4;
                    _arg4 = data.readDouble();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                    reply.writeNoException();
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.yetao.android.library.sdk28.IBean {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            /**
             * 演示一些可用作参数的基本类型并以AIDL返回值。
             */
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    //一下是序列化数据的写入,没有写入字段名,所以在读取的时候必须按顺序
                    //所以不能用于磁盘持久化中,一旦文件字段增删查改,反序列化将出现问题
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(((aBoolean) ? (1) : (0)));
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);
                    mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    /**
     * 演示一些可用作参数的基本类型并以AIDL返回值。
     */
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}

(2)Parcel创建

上面介绍了aidl通过Parcel写入数据来做交互,其实Parcel在java和c++层都对应有具体的操作,java层提供接口,实现在c++层。

先来看java层的Parcel初始化

Parcel.java

    /**
    * @param nativePtr 是c++层Parcel对应的地址
    **/
   private Parcel(long nativePtr) {
        if (DEBUG_RECYCLE) {
            mStack = new RuntimeException();
        }
        //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);
        //调用初始化
        init(nativePtr);
    }  


    private void init(long nativePtr) {
        //如果传入了地址,则直接指向该地址
        if (nativePtr != 0) {
            mNativePtr = nativePtr;
            mOwnsNativeParcelObject = false;
        } else {
            //如果没有传入,则调用本地方法创建
            mNativePtr = nativeCreate();
            mOwnsNativeParcelObject = true;
        }
    }

    private static native long nativeCreate();

我们来深入c++层分析是怎么创建的

//  /frameworks/base/core/jni/android_os_Parcel.cpp
//nativeCreate映射到android_os_Parcel_create方法
{"nativeCreate",              "()J", (void*)android_os_Parcel_create},

static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
    //创建出c++层Parcel对象
    Parcel* parcel = new Parcel();
    //将指针地址转换成long型地址返回java层,被mNativePtr持有
    return reinterpret_cast<jlong>(parcel);
}


(2)Parcel的写入

说道写入我们先来c++层看看Pracel的几个变量

/frameworks/base/core/jni/android_os_Parcel.cpp

uint8_t*            mData;//数据存储的指针
size_t              mDataSize;//数据的大小
size_t              mDataCapacity;//数据的容量
mutable size_t      mDataPos;//数据存储的指针位置

后面围绕着这几个变量,来对数据进行写入操作,以writeInt()为例,还是从java到c++层分析

Parcel.java

    /** 
     * 在当前dataPosition()处将整数值写入包裹,
     * 如果需要,可增加dataCapacity()。
     */
    public final void writeInt(int val) {
        nativeWriteInt(mNativePtr, val);
    }
    //传入c++Parcel对象指针和要写入的值
    private static native void nativeWriteInt(long nativePtr, int val);

上面java层没有实现具体操作,具体操作还是在c++层实现

/frameworks/base/core/jni/android_os_Parcel.cpp
//将nativeWriteInt方法映射到android_os_Parcel_writeInt
{"nativeWriteInt", "(JI)V", (void*)android_os_Parcel_writeInt},

static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
    //从long型指针强转成Parcel指针
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        //实际调用parcel的writeInt32方法写入
        const status_t err = parcel->writeInt32(val);
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

jni层调用Parcel的writeInt32(val)来写入值

/frameworks/native/libs/binder/Parcel.cpp

status_t Parcel::writeInt32(int32_t val)
{
    return writeAligned(val);
}

template<class T>
status_t Parcel::writeAligned(T val) {
    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
    //检查当前是否大于容量,如果大于就扩容,之后直接跳转到写入
    if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
        *reinterpret_cast<T*>(mData+mDataPos) = val;
        return finishWrite(sizeof(val));
    }

    status_t err = growData(sizeof(val));
    if (err == NO_ERROR) goto restart_write;
    return err;
}

writeAligned主要做了以下几步:
1.判断写入容量是否足够
2.不够的话,先扩容然后再写入;如果容量够,直接写入
3.写入数据完成后,写入数据长度。

写入String类型数据的有点不一样,来看看如何写入,直接看c++层

/frameworks/base/core/jni/android_os_Parcel.cpp
//映射方法
{"nativeWriteString",  "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},

static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        status_t err = NO_MEMORY;
        if (val) {
            //用掉writeString16写入str
            const jchar* str = env->GetStringCritical(val, 0);
            if (str) {
                err = parcel->writeString16(
                    reinterpret_cast<const char16_t*>(str),
                    env->GetStringLength(val));
                env->ReleaseStringCritical(val, str);
            }
        } else {
            err = parcel->writeString16(NULL, 0);
        }
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

主要步骤:
1.找到c++的Parcel对象
2.env获取到string值
3.调用Parcel的writeString方法写入数据
4.释放String

/frameworks/native/libs/binder/Parcel.cpp

status_t Parcel::writeString16(const std::unique_ptr<String16>& str)
{
    if (!str) {
        return writeInt32(-1);
    }

    return writeString16(*str);
}

status_t Parcel::writeString16(const String16& str)
{
    return writeString16(str.string(), str.size());
}

status_t Parcel::writeString16(const char16_t* str, size_t len)
{
    if (str == NULL) return writeInt32(-1);
    //先写入长度
    status_t err = writeInt32(len);
    if (err == NO_ERROR) {
        len *= sizeof(char16_t);
        uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
        if (data) {
            memcpy(data, str, len);
            *reinterpret_cast<char16_t*>(data+len) = 0;
            return NO_ERROR;
        }
        err = mError;
    }
    return err;
}

主要步骤:
1.先写入长度值
2.调用writeInplace进行补位操作,确保是4的倍数
3.调用memcpy将str复制到data中
4.结束写入0

(4) Parcel的读取

直接来看对String类型进行读取,我们不看映射直接来看操作方法

/frameworks/base/core/jni/android_os_Parcel.cpp
static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        size_t len;
        const char16_t* str = parcel->readString16Inplace(&len);
        if (str) {
            return env->NewString(reinterpret_cast<const jchar*>(str), len);
        }
        return NULL;
    }
    return NULL;
}

主要步骤:
1.获取c++层Parcel对象
2.通过Parcel的readString16Inplace方法读取,获取到长度和字符串
3.转换为string返回

/frameworks/native/libs/binder/Parcel.cpp

const char16_t* Parcel::readString16Inplace(size_t* outLen) const
{
    int32_t size = readInt32();
    // watch for potential int overflow from size+1
    if (size >= 0 && size < INT32_MAX) {
        *outLen = size;
        const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
        if (str != NULL) {
            return str;
        }
    }
    *outLen = 0;
    return NULL;
}



主要步骤:
1.读取字符串长度
2.通过readInplace读取值,由于最后写入了0所以需要+1
3.读取完成返回

const void* Parcel::readInplace(size_t len) const
{
    if (len > INT32_MAX) {
        // don't accept size_t values which may have come from an
        // inadvertent conversion from a negative int.
        return NULL;
    }

    if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
            && len <= pad_size(len)) {
        if (mObjectsSize > 0) {
            status_t err = validateReadData(mDataPos + pad_size(len));
            if(err != NO_ERROR) {
                // Still increment the data position by the expected length
                mDataPos += pad_size(len);
                ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
                return NULL;
            }
        }

        const void* data = mData+mDataPos;
        mDataPos += pad_size(len);
        ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
        return data;
    }
    return NULL;
}

根据长度以及补位相关,计算得到指针位置mDataPos,并返回指针,完成整个读取。

小结:相对于Serializable,Parcelable在序列化过程中,产生的临时变量很少,也没用到反射。



三、Serializable和Parcelable对比

-SerializableParcelable
变量数序列化过程中产生大量临时变量少量
反射使用未使用
实现难易度相对简单相对难一点
缓存方式适用于所有场景不适用于磁盘等持久化
内存消耗
读写数据形式IO流读取内存直接读取
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值