深入c++层分析Serializable和Parcelable的区别
文章目录
- 深入c++层分析Serializable和Parcelable的区别
- 一、Serializable的源码分析
- 1、首先来看一下ObjectOutputStream产生的中间变量
- 2、序列化过程
- (1)有多个构造函数,这里选取一个public来分析
- (2)verifySubclass方法
- (3)再来看writeStreamHeader方法,写入了哪些头信息
- (4)通常我们构造了ObjectOutputStream oos = new ObjectOutputStream(out)后,会调用writeObject(Object)来写入对象
- (5)writeOrdinaryObject
- (6)写入描述信息
- (8)写入字段信息
- (9)举几个基础类型写入
- (10)BlockDataOutputStream类,在这里我就不分析了,喜欢深入了解的朋友,可以继续查看BlockDataOutputStream的相关write*方法
- 一.Parcelable的源码分析
- 三、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对比
- | Serializable | Parcelable |
---|---|---|
变量数 | 序列化过程中产生大量临时变量 | 少量 |
反射 | 使用 | 未使用 |
实现难易度 | 相对简单 | 相对难一点 |
缓存方式 | 适用于所有场景 | 不适用于磁盘等持久化 |
内存消耗 | 多 | 少 |
读写数据形式 | IO流读取 | 内存直接读取 |