1 简介
在Android组件间或者跨进程组件间要传递数据都是通过使用 Intent.putExtra() 或者 Bundle.putXXXExtra()方法进行,这些方法无法支持传递对象的引用,而只支持基本平台类型和实现了Serializable或者Parcelable接口的类对象。
Serializable接口我们在《Android序列化(一) 之 Serializable》中已经介绍过,它是Java提供的可将对象序列化成字节流进行文件持久化存储或网络传输,也可将字节流反序列化成新的对象。
Parcelable接口在android.os包中,实现它便能让对象支持Parcel。简单地理解就是实现Parcelable接口便能使一个自定义类在Android组件间传递具有序列化和反序列化的能力。
Parcel类也在android.os包中,它不是通用序列化机制,而是一种可通过IBinder高性能传输数据和对象的容器,或者说是它是Android里特殊序列化机制。Parcel内部采用共享内存的方式实现用户空间和内核空间的数据交换,本质是Native层的共享内存。
凡通过Parcel包装后的数据都可以通过在Binder进程间通信IPC中进行端和端的数据交互,一端将数据Parcel化后写入到一个共享内存中,另一端通过Parcel可以从这块共享内存中读出字节流还原成原来的数据。Parcel支持基础平台数据类型,也支持实现了Parcelable接口的对象,也支持一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。在Android里AIDL也用到了Parcel进行数据封装。
2 示例
public class Student implements Parcelable {
private int id;
private String name;
private boolean verified;
private Phone mainPhone;
private List<Phone> phones;
private Map<Integer, String> tags;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setVerified(boolean verified) {
this.verified = verified;
}
public boolean isVerified() {
return verified;
}
public Phone getMainPhone() {
return mainPhone;
}
public void setMainPhone(Phone phone) {
this.mainPhone = phone;
}
public List<Phone> getPhones() {
return phones;
}
public void setPhones(List<Phone> phones) {
this.phones = phones;
}
public Map<Integer, String> getTags() {
return tags;
}
public void setTags(Map<Integer, String> tags) {
this.tags = tags;
}
public Student() {
}
private Student(Parcel in) {
id = in.readInt();
name = in.readString();
verified = in.readByte() == 1; // API level 29后可以直接使用 readBoolean 支持 Boolean类型
mainPhone = in.readParcelable(Phone.class.getClassLoader());
phones = in.readArrayList(Phone.class.getClassLoader());
// 另外一种方式读取List,需要List先初始化
// phones = new ArrayList<>();
// in.readList(phones, Phone.class.getClassLoader());
// 另外一种方式读取List,但是需要配合 write 时使用了 writeTypedList,这里才应该使用 createTypedArrayList 传入 CREATOR
// phones = in.createTypedArrayList(Phone.CREATOR);
// 另外一种方式读取List,但是需要配合 write 时使用了 writeTypedList,这里才应该使用 readTypedList 传入 CREATOR
// 而且需要List先初始化
// phones = new ArrayList<>();
// in.readTypedList(phones, Phone.CREATOR);
// 如果Map内是基本数据类型,传入的ClassLoader可为null,
// 如果key或value其中一个或两个都是同一个实现Parcelable的类,传入对应类的ClassLoader,
// 如果key和value两个是不同的类,传什么都不对
tags = in.readHashMap(null);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeByte((byte)(verified? 1: 0)); // API level 29后可以直接使用 writeBoolean 支持 Boolean类型
dest.writeParcelable(mainPhone, 0);
dest.writeList(phones);
// 另一种序列化方式,反序列化时需要使用 createTypedArrayList 或 readTypedList
// dest.writeTypedList(phones);
dest.writeMap(tags);
}
public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
public Student createFromParcel(Parcel in) {
return new Student(in);
}
public Student[] newArray(int size) {
return new Student[size];
}
};
static class Phone implements Parcelable {
private String number;
private String type;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Phone() {
}
private Phone(Parcel in) {
number = in.readString();
type = in.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(number);
dest.writeString(type);
}
public static final Parcelable.Creator<Phone> CREATOR = new Parcelable.Creator<Phone>() {
public Phone createFromParcel(Parcel in) {
return new Phone(in);
}
public Phone[] newArray(int size) {
return new Phone[size];
}
};
}
}
数据发送方:
Student student = new Student();
student.setId(1001);
student.setName("子云心");
student.setVerified(true);
Student.Phone mainPhone = new Student.Phone();
mainPhone.setType("MAIN");
mainPhone.setNumber("99999999999");
student.setMainPhone(mainPhone);
List<Student.Phone> phones = new ArrayList<>();
Student.Phone phone1 = new Student.Phone();
phone1.setType("MOBILE");
phone1.setNumber("12345678910");
phones.add(phone1);
Student.Phone phone2 = new Student.Phone();
phone2.setType("HOME");
phone2.setNumber("0000-1234567");
phones.add(phone2);
student.setPhones(phones);
Map<Integer, String> tags = new HashMap();
tags.put(0, "三好学生");
tags.put(1, "体育达人");
student.setTags(tags);
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
intent.putExtra("studentData", student);
// 使用 Bundle 也可以,intent.putExtra内部也是使用了Bundle
Bundle args = new Bundle();
args.putParcelable("studentData2", student);
intent.putExtra("bundleData", args);
startActivity(intent);
数据接收方:
Student student = getIntent().getParcelableExtra("studentData");
Bundle bundle = getIntent().getBundleExtra("bundleData");
Student student2 = bundle.getParcelable("studentData2");
3 类的结构
实现Parcelable接口的类,必须要重写describeContents 和 writeToParcel 两个方法,必须有一个参数是Parcel类型的构造方法,以及必须要声明一个非空的、名字必须是CREATOR的、类型是Parcelable.Creator<T>的静态变量。
3.1 describeContents方法
目前describeContents方法的返回值要么是0,要么是Parcelable.CONTENTS_FILE_DESCRIPTOR(0x0001)。Parcelable.CONTENTS_FILE_DESCRIPTOR表示Paracelable里面含一些特殊的文件描述信息。在大多数情况下返回0即可。
3.2 writeToParcel方法 和 带Parcel参数的构造方法
writeToParcel方法是实现序列化写操作的地方,它返回一个Parcel对象。带Parcel参数的构造方法是实现反序列化读操作的地方,它接收一个Parcel对象。Parcel对象的写入和读取的顺序必须保持一致,否则会发生数值错误或者类型异常崩溃情况。序列化和反序列化由一系列Parcel的write和read方法支持,例如常用的方法有:
byte类型
序列化方法:???????? void writeByte(byte val)
反序列化方法:???? byte readByte()
boolean类型(API level 29后才支持,在之前可以使用byte是1或者0来代替,如上面示例)
序列化方法:???????? void writeBoolean(boolean val)
反序列化方法:???? boolean readBoolean()
int类型
序列化方法:???????? void writeInt(int val)
反序列化方法:???? int readInt()
String类型
序列化方法:???????? void writeString(String val)
反序列化方法:???? String readString()??
等等一系列基础平台类型
序列化方法:???????? void writeXXX(XXX val)
反序列化方法:???? XXX readXXX()
实现了Parcelable的类
序列化方法:???????? void writeParcelable(@Nullable Parcelable p, int parcelableFlags)
反序列化方法:???? <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader)
Map<K, V>类型
序列化方法:???????? void writeMap(@Nullable Map val)
反序列化方法1,内部会new一个新的HashMap对象:
HashMap readHashMap(@Nullable ClassLoader loader)
反序列化方法2,内部不会new出新对象,输入的outVal必须提前初始化:
void readMap(@NonNull Map outVal, @Nullable ClassLoader loader)?
List<E>类型(使用 ClassLoader 序列化和反序列化)
序列化方法:???????? void writeList(@Nullable List val)
反序列化方法1,内部会new一个新的ArrayList对象:
ArrayList readArrayList(@Nullable ClassLoader loader)
反序列化方法2,内部不会new出新对象,输入的outVal必须提前初始化:
void readList(@NonNull List outVal, @Nullable ClassLoader loader)
List<E>类型(使用Parcelable.Creator序列化和反序列化)
序列化方法:???????? <T extends Parcelable> void writeTypedList(@Nullable List<T> val)
反序列化方法1,内部会new一个新的ArrayList对象:
<T> ArrayList<T> createTypedArrayList(@NonNull Parcelable.Creator<T> c)? ? ??
反序列化方法2,内部不会new出新对象,输入的outVal必须提前初始化:
<T> void readTypedList(@NonNull List<T> list, @NonNull Parcelable.Creator<T> c)
3.3 CREATOR变量
CREATOR变量用于从Parcel中取出指定的数据类型,它是一个非空的、名字必须是CREATOR的、类型是Parcelable.Creator<T>接口的静态变量,接口内有两个方法,其中createFromParcel方法返回的便是反序列化时调用到的带Parcel参数的构造方法。
4 startActivity通过Intent传递参数过程
根据上面示例得知,可以通过Intent.putExtra或者Bundle.putParcelable将实现了Parcelable接口的对象添加到Intent中,从而进行组件间数据传递。Intent.putExtra其实也是调用了Bundle.putBundle。
Intent.java
public @NonNull Intent putExtra(String name, @Nullable Bundle value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putBundle(name, value);
return this;
}
Bundle.java
public void putBundle(@Nullable String key, @Nullable Bundle value) {
??? unparcel();
??? mMap.put(key, value);
}
public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
??? unparcel();
??? mMap.put(key, value);
??? mFlags &= ~FLAG_HAS_FDS_KNOWN;
}
无论是Bundle.putBundle还是Bundle.putParcelable,都是先调用父类的unparcel方法。
BaseBundle.java
void unparcel() {
synchronized (this) {
final Parcel source = mParcelledData;
if (source != null) {
initializeFromParcelLocked(source, /*recycleParcel=*/ true, mParcelledByNative);
} else {
if (DEBUG) {
Log.d(TAG, "unparcel "
+ Integer.toHexString(System.identityHashCode(this))
+ ": no parcelled data");
}
}
}
}
unparcel方法内,此时mParcelledData对象还是为null状态(mParcelledData下面会进行介绍),所以unparcel方法此时如果是DEBUG则只是打印了一行日志而已。
在调用unparcel方法后putBundle和putParcelable都是将对象添加到一个ArrayMap<String, Object>中去,而Bundle对象最后会保存于Intent中的mExtras变量中。
在进行startActivity时就会将Intent对象传入,startActivity实质是会进行一次AMS(Android10以下是ActivityManagerService/AMS,Android10之后是ActivityTaskManagerService/ATMS)的跨进程通信,这时就会将Intent内的数据也一同传递过去,
Activity.java
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
……
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
……
}
Instrumentation.java(源码基于Android10,使用的是ATMS)
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
……
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
……
}
ActivityTaskManager.java
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
}
};
ActivityTaskManager.getService()返回的是实现了IActivityTaskManager接口的ActivityTaskManagerService。IActivityTaskManager位于android/app/IActivityTaskManager.aidl,它没有对应的Java代码,它是一个AIDL文件,返回的结果是 Binder 的代理类 , 该类主要作用是使用了Binder机制 , 进行进程间通信。
IActivityTaskManager生成的Java源码我们无法查看到,但能想像到进行IPC时传入的Intent肯定是先进行序列化的,所以我们可以进行模拟创建一个AILD并在接口方法参数传入一个Intent对象。如:
自定义的IActivityTaskManager.aidl,它是一段模拟IActivityTaskManager的伪代码
package com.zyx.myapplication;
interface IActivityTaskManager {
??? int startActivity(in Intent intent);
}
使用AndroidStudio编译自动生成IActivityTaskManager.java
public interface IActivityTaskManager extends android.os.IInterface {
……
public static abstract class Stub extends android.os.Binder implements com.zyx.myapplication.IActivityTaskManager {
……
@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;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_startActivity: {
data.enforceInterface(descriptor);
android.content.Intent _arg0;
if ((0!=data.readInt())) {
// 关键代码3,这里传入序列化后的数据创建一个新的Inetnt对象
_arg0 = android.content.Intent.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
int _result = this.startActivity(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.zyx.myapplication.IActivityTaskManager {
……
private android.os.IBinder mRemote;
@Override public int startActivity(android.content.Intent intent) throws android.os.RemoteException {
// 关键代码1,创建2个Parcel对象,用于记录序列化数据和序列化结果
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((intent!=null)) {
_data.writeInt(1);
// 关键代码2,这里进行了序列化的操作
intent.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_startActivity, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().startActivity(intent);
}
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
……
}
……
}
……
}
从生成的代码可见:
关键代码1中,IActivityTaskManager$Stub$Proxy#startActivity方法开始先通过Parcel的obtain方法先创建两个Parcel对象,用于后面记录序列化数据和序列化结果。
关键代码2中,IActivityTaskManager$Stub$Proxy#startActivity方法传入的Intent参数进行调用Intent的writeToParcel方法,该方法就是序列化的开始(下面会介绍内在过程),序列化的结果通过_data输出,最后通过mRemote.transact将序列化后的_data传递到ActivityTaskManagerService进程去。
从AIDL的运行原理得知,当Client端发起跨进程请求时,远程请求会通过系统底层封装后交由onTransact方法来处理。onTransact方法判断传入的code,即在关键代码2后传入的 TRANSACTION_startActivity 找到关健代码3的地方,关键代码3中,传入将序列化后的数据通过 Intent.CREATOR.createFromParcel创建一个新的Inetnt对象。
Intent.java
public static final @android.annotation.NonNull Parcelable.Creator<Intent> CREATOR
= new Parcelable.Creator<Intent>() {
public Intent createFromParcel(Parcel in) {
return new Intent(in);
}
public Intent[] newArray(int size) {
return new Intent[size];
}
};
protected Intent(Parcel in) {
readFromParcel(in);
}
public void readFromParcel(Parcel in) {
setAction(in.readString8());
mData = Uri.CREATOR.createFromParcel(in);
mType = in.readString8();
mIdentifier = in.readString8();
mFlags = in.readInt();
mPackage = in.readString8();
mComponent = ComponentName.readFromParcel(in);
……
mExtras = in.readBundle();
}
readFromParcel方法中,关键是最后一行,readBundle 用于创建一个新的Bundle对象赋予给mExtras变量。
Parcel.java
public final Bundle readBundle(@Nullable ClassLoader loader) {
int length = readInt();
……
final Bundle bundle = new Bundle(this, length);
if (loader != null) {
bundle.setClassLoader(loader);
}
return bundle;
}
Bundle.java
public Bundle(Parcel parcelledData, int length) {
super(parcelledData, length);
mFlags = FLAG_ALLOW_FDS;
maybePrefillHasFds();
}
BaseBundle.java
BaseBundle(Parcel parcelledData, int length) {
readFromParcelInner(parcelledData, length);
}
private void readFromParcelInner(Parcel parcel, int length) {
……
int offset = parcel.dataPosition();
parcel.setDataPosition(MathUtils.addOrThrow(offset, length));
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.appendFrom(parcel, offset, length);
p.adoptClassCookies(parcel);
if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this))
+ ": " + length + " bundle bytes starting at " + offset);
p.setDataPosition(0);
mParcelledData = p;
mParcelledByNative = isNativeBundle;
}
Bundle的构造方法调用了其父类BaseBundle的构造方法,然后是调用了readFromParcelInner方法,readFromParcelInner方法里复制了一个新的Parcel对象然后赋予了mParcelledData变量,它保存的便是序列化后的数据。在反序列化过程时(下面会介绍内在过程)便是通过mParcelledData来还原成原来的数据。
5 Parcelable序列化过程
从上面Intent传递参数过程得知,Intent的writeToParcel方法是序列化的开始,我们来看源码:
Intent.java
public void writeToParcel(Parcel out, int flags) {
out.writeString8(mAction);
Uri.writeToParcel(out, mData);
out.writeString8(mType);
out.writeString8(mIdentifier);
out.writeInt(mFlags);
out.writeString8(mPackage);
ComponentName.writeToParcel(mComponent, out);
……
out.writeBundle(mExtras);
}
Intent里的writeToParcel方法前面会进行一些Action、Type、Flags、Package等的写入,最后一行会调用到Parcel的writeBundle方法。
Parcel.java
public final void writeBundle(@Nullable Bundle val) {
……
val.writeToParcel(this, 0);
}
Bundle.java
public void writeToParcel(Parcel parcel, int flags) {
??? final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
??? try {
??????? super.writeToParcelInner(parcel, flags);
??? } finally {
??????? parcel.restoreAllowFds(oldAllowFds);
??? }
}
Bundle的父类是BaseBundle,所以再来看下BaseBundle# writeToParcelInner。
BaseBundle.java
void writeToParcelInner(Parcel parcel, int flags) {
……
final ArrayMap<String, Object> map;
synchronized (this) {
// unparcel() can race with this method and cause the parcel to recycle
// at the wrong time. So synchronize access the mParcelledData's content.
if (mParcelledData != null) {
if (mParcelledData == NoImagePreloadHolder.EMPTY_PARCEL) {
parcel.writeInt(0);
} else {
int length = mParcelledData.dataSize();
parcel.writeInt(length);
parcel.writeInt(mParcelledByNative ? BUNDLE_MAGIC_NATIVE : BUNDLE_MAGIC);
parcel.appendFrom(mParcelledData, 0, length);
}
return;
}
map = mMap;
}
……
int lengthPos = parcel.dataPosition();
parcel.writeInt(-1); // dummy, will hold length
parcel.writeInt(BUNDLE_MAGIC);
int startPos = parcel.dataPosition();
// 关键代码,将数据写入parcel
parcel.writeArrayMapInternal(map);
int endPos = parcel.dataPosition();
// Backpatch length
parcel.setDataPosition(lengthPos);
int length = endPos - startPos;
parcel.writeInt(length);
parcel.setDataPosition(endPos);
}
上面我们知道,无论是Bundle.putBundle还是Bundle.putParcelable,都是将对象添加到一个ArrayMap<String, Object>类型的mMap中去,这里的parcel.writeArrayMapInternal便是传入这个ArrayMap。
Parcel.java
void writeArrayMapInternal(@Nullable ArrayMap<String, Object> val) {
??? ……
??? final int N = val.size();
??? writeInt(N);
……
??? int startPos;
??? for (int i=0; i<N; i++) {
??????? if (DEBUG_ARRAY_MAP) startPos = dataPosition();
??????? writeString(val.keyAt(i));
??????? writeValue(val.valueAt(i));
??????? ……
??? }
}
WriteArrayMapInternal方法先写入Map的长度,然后遍历Map写入每一项的key和value。着重看写value部分。
public final void writeValue(@Nullable Object v) {
??? if (v == null) {
??????? writeInt(VAL_NULL);
??? } else 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 Map) {
??????? writeInt(VAL_MAP);
??????? writeMap((Map) v);
??? } else if (v instanceof Bundle) {
??????? // Must be before Parcelable
??????? writeInt(VAL_BUNDLE);
??????? writeBundle((Bundle) v);
??? } else if (v instanceof PersistableBundle) {
??????? writeInt(VAL_PERSISTABLEBUNDLE);
??????? writePersistableBundle((PersistableBundle) v);
??? } else if (v instanceof Parcelable) {
??????? // 关键代码,实现了Parcelable的类的写入
??????? writeInt(VAL_PARCELABLE);
????? ??writeParcelable((Parcelable) v, 0);
??? } else if (v instanceof Short) {
??????? writeInt(VAL_SHORT);
??????? writeInt(((Short) v).intValue());
??? } else if (v instanceof XXX) {
?????? ……
} else {
??????? ……
??? }
}
writeValue内根据Object的类型进行不同的写入,当发现对象是Parcelable 后便再调用了writeParcelable方法。
public final void writeParcelable(@Nullable Parcelable p, int parcelableFlags) {
??? ……
??? writeParcelableCreator(p);
??? p.writeToParcel(this, parcelableFlags);
}
Parcelable.java
public interface Parcelable {
??? public void writeToParcel(Parcel dest, @WriteFlags int flags);
}
writeParcelable方法最后一行便是调用了Parcelable的writeToParcel方法,也就是我们手动实现的序列化的地方。
6 Parcelable反序列化过程
从上面Intent传递参数过程得知,在新的Activity里包含着一个新的Intent对象,而Intent内部的Bundle的mParcelledData字段便是保存了前面序列化后的数据。了解反序列化的过程,从Intent.getParcelableExtra或Bundle.getParcelable开始:
Intent.java
public @Nullable <T extends Parcelable> T getParcelableExtra(String name) {
??? return mExtras == null ? null : mExtras.<T>getParcelable(name);
}
Bundle.java
public <T extends Parcelable> T getParcelable(@Nullable String key) {
unparcel();
Object o = mMap.get(key);
if (o == null) {
return null;
}
try {
return (T) o;
} catch (ClassCastException e) {
typeWarning(key, o, "Parcelable", e);
return null;
}
}
getParcelable方法中,首先通过unparcel方法将数据还原成新的对象,然后通过key读取Map后返回对象。所以关键就是unparcel方法。
BaseBundle.java
void unparcel() {
synchronized (this) {
final Parcel source = mParcelledData;
if (source != null) {
initializeFromParcelLocked(source, /*recycleParcel=*/ true, mParcelledByNative);
} else {
if (DEBUG) {
Log.d(TAG, "unparcel "
+ Integer.toHexString(System.identityHashCode(this))
+ ": no parcelled data");
}
}
}
}
因为前面的原因,这次mParcelledData变量已经不为空,所以接下来会调用到initializeFromParcelLocked方法。
private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel, boolean parcelledByNative) {
……
ArrayMap<String, Object> map = mMap;
if (map == null) {
map = new ArrayMap<>(count);
} else {
map.erase();
map.ensureCapacity(count);
}
try {
if (parcelledByNative) {
parcelledData.readArrayMapSafelyInternal(map, count, mClassLoader);
} else {
parcelledData.readArrayMapInternal(map, count, mClassLoader);
}
} catch (BadParcelableException e) {
……
}
……
}
initializeFromParcelLocked方法内,判断parcelledByNative是否为true来决定使用Parcel的readArrayMapSafelyInternal方法还是readArrayMapInternal方法来进行反序列化输出ArrayMap参数。
Parcel.java
void readArrayMapSafelyInternal(@NonNull ArrayMap outVal, int N, @Nullable ClassLoader loader) {
……
while (N > 0) {
String key = readString();
if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read safe #" + (N-1) + ": key=0x"
+ (key != null ? key.hashCode() : 0) + " " + key);
Object value = readValue(loader);
outVal.put(key, value);
N--;
}
}
void readArrayMapInternal(@NonNull ArrayMap outVal, int N, @Nullable ClassLoader loader) {
……
int startPos;
while (N > 0) {
if (DEBUG_ARRAY_MAP) startPos = dataPosition();
String key = readString();
Object value = readValue(loader);
if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + " "
+ (dataPosition()-startPos) + " bytes: key=0x"
+ Integer.toHexString((key != null ? key.hashCode() : 0)) + " " + key);
outVal.append(key, value);
N--;
}
outVal.validate();
}
无论是readArrayMapSafelyInternal方法还是readArrayMapInternal方法,都是根据数据长度进行循环调用readValue方法进行读取数据。
public final Object readValue(@Nullable ClassLoader loader) {
int type = readInt();
switch (type) {
case VAL_NULL:
return null;
case VAL_STRING:
return readString();
case VAL_INTEGER:
return readInt();
case VAL_MAP:
return readHashMap(loader);
case VAL_PARCELABLE:
// 关键代码,实现了Parcelable的类型的读取
return readParcelable(loader);
……
}
readValue方法对应序列化时的writeValue方法,会根据序列化时标明的数据的类型进行不同的读取,当发现类型是Parcelable后便再调用了readParcelable方法。
public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
// 关键代码1,调到readParcelableCreator方法去获取我们类中的CREATOR
Parcelable.Creator<?> creator = readParcelableCreator(loader);
if (creator == null) {
return null;
}
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
Parcelable.ClassLoaderCreator<?> classLoaderCreator =
(Parcelable.ClassLoaderCreator<?>) creator;
return (T) classLoaderCreator.createFromParcel(this, loader);
}
// 关键代码2,调用CREATOR里的createFromParcel方法,该方法便是返回带Parcel的构造方法,也就是反序列化的地方
return (T) creator.createFromParcel(this);
}
public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
……
try {
ClassLoader parcelableClassLoader = (loader == null ? getClass().getClassLoader() : loader);
Class<?> parcelableClass = Class.forName(name, false, parcelableClassLoader);
……
// 关键代码,指定字段名一定是 CREATOR
Field f = parcelableClass.getField("CREATOR");
……
Class<?> creatorType = f.getType();
……
creator = (Parcelable.Creator<?>) f.get(null);
} catch (IllegalAccessException e) {
……
} catch (ClassNotFoundException e) {
……
} catch (NoSuchFieldException e) {
……
}
……
return creator;
}
关键代码1中,readParcelableCreator方法通过传入的ClassLoader作为参数,通过反射获取到我们在类中定义的 CREATOR变量,这里也解释了为什么实现Parcelable接口后,除了实现两个必要的接口方法外,还需要声明一定名称必须是CREATOR变量的原因。在获取了CREATOR后,便在关键代码2中,调用CREATOR里的createFromParcel方法,我们在该方法中返回带Parcel的构造方法,也就是我们手动实现反序列化的地方。
7 Parcel原理
从上面的介绍可知,Parcel对象通过obtain方法创建,序列化和反序列化的实际上最后的操作便是我们类中自己实现的writeToParcel方法和带Parcel参数的构造方法中通过一系列writeXXX 和readXXX方法来完成。下面来看看Parcel的源码情况。
7.1 Java层的Parcel类
obtain方法创建Parcel对象:
Parcel.java
public static Parcel obtain() {
??? final Parcel[] pool = sOwnedPool;
??? synchronized (pool) {
??????? Parcel p;
??????? for (int i=0; i<POOL_SIZE; i++) {
??????????? p = pool[i];
??????????? if (p != null) {
??????????????? pool[i] = null;
??????????????? if (DEBUG_RECYCLE) {
??????????????????? p.mStack = new RuntimeException();
??????????????? }
??????????????? p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
??????????????? return p;
??????????? }
??????? }
??? }
// 缓存中没有Parcel对象,则传入0创建一个新的
??? return new Parcel(0);
}
obtain方法先尝试从缓存数组中去获取一个Parcel对象,若缓存中没有则传入0创建一个新的对象。
private long mNativePtr; // 用于存放 Native 层的 Parcel 对象的指针地址
private Parcel(long nativePtr) {
??? if (DEBUG_RECYCLE) {
??????? mStack = new RuntimeException();
??? }
??? init(nativePtr);
}
private void init(long nativePtr) {
??? if (nativePtr != 0) {
??????? mNativePtr = nativePtr;
??????? mOwnsNativeParcelObject = false;
??? } else {
??????? mNativePtr = nativeCreate();
??????? mOwnsNativeParcelObject = true;
??? }
}
private static native long nativeCreate();
Parcel的构造函数调用了init方法进行初始化Parcel,如果传入0,则通过nativeCreate方法创建,并返回一个指针地址数值赋值给mNativePtr变量。其中,nativeCreate方法是一个Native方法。而我们进行序列化和反序列化的一系列writeXXX和readXXX方法其实也是有对应的Native方法,Parcel类只是一个代理的空壳类:
public final void writeInt(int val) {
??? nativeWriteInt(mNativePtr, val);
}
public final void writeLong(long val) {
??? nativeWriteLong(mNativePtr, val);
}
public final void writeFloat(float val) {
??? nativeWriteFloat(mNativePtr, val);
}
public final void writeDouble(double val) {
??? nativeWriteDouble(mNativePtr, val);
}
public final void writeString(@Nullable String val) {
??? mReadWriteHelper.writeString(this, val);
}
public final int readInt() {
??? return nativeReadInt(mNativePtr);
}
public final long readLong() {
??? return nativeReadLong(mNativePtr);
}
public final float readFloat() {
??? return nativeReadFloat(mNativePtr);
}
public final double readDouble() {
??? return nativeReadDouble(mNativePtr);
}
public final String readString() {
??? return mReadWriteHelper.readString(this);
}
public static class ReadWriteHelper {
??? public static final ReadWriteHelper DEFAULT = new ReadWriteHelper();
??? public void writeString(Parcel p, String s) {
??????? nativeWriteString(p.mNativePtr, s);
??? }
??? public String readString(Parcel p) {
??????? return nativeReadString(p.mNativePtr);
??? }
}
private static native void nativeWriteInt(long nativePtr, int val);
private static native void nativeWriteLong(long nativePtr, long val);
private static native void nativeWriteFloat(long nativePtr, float val);
private static native void nativeWriteDouble(long nativePtr, double val);
static native void nativeWriteString(long nativePtr, String val);
private static native int nativeReadInt(long nativePtr);
private static native long nativeReadLong(long nativePtr);
private static native float nativeReadFloat(long nativePtr);
private static native double nativeReadDouble(long nativePtr);
static native String nativeReadString(long nativePtr);
7.2 C++层的android_os_Parcel类
正常情况下,Android Studio开发时所下载的SDK源码里并不会包含Native层的代码,所以我们如果需要查阅C++层的代码需要自己另外进行下载,或者通过在线查阅,如:AndroidXRef 。回来正题,Parcel.java中所调用的Native代码的实现在android_os_Parcel.cpp中,继续查看关键方法的实现。
\frameworks\base\core\jni\android_os_Parcel.cpp
static const JNINativeMethod gParcelMethods[] = {
……
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
……
{"nativeWriteInt", "(JI)V", (void*)android_os_Parcel_writeInt},
{"nativeWriteLong", "(JJ)V", (void*)android_os_Parcel_writeLong},
{"nativeWriteFloat", "(JF)V", (void*)android_os_Parcel_writeFloat},
{"nativeWriteDouble", "(JD)V", (void*)android_os_Parcel_writeDouble},
{"nativeWriteString", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
……
{"nativeReadInt", "(J)I", (void*)android_os_Parcel_readInt},
{"nativeReadLong", "(J)J", (void*)android_os_Parcel_readLong},
{"nativeReadFloat", "(J)F", (void*)android_os_Parcel_readFloat},
{"nativeReadDouble", "(J)D", (void*)android_os_Parcel_readDouble},
{"nativeReadString", "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
……
};
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz) {
// 创建 native 层的 Parcel 对象
Parcel* parcel = new Parcel();
// 返回其指针的long值
return reinterpret_cast<jlong>(parcel);
}
static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val)
{
// nativePtr 是 android_os_Parcel_create 返回的 Parcel 对象的指针值,这里强转回 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);
}
}
}
static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
{
// nativePtr 是 android_os_Parcel_create 返回的 Parcel 对象的指针值,这里强转回 Parcel 指针
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
status_t err = NO_MEMORY;
if (val) {
// 获取需要写入的字符串
const jchar* str = env->GetStringCritical(val, 0);
if (str) {
// 使用Parcel指针调用其 writeString16() 方法写入数据
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);
}
}
}
static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr)
{
// nativePtr 是 android_os_Parcel_create 返回的 Parcel 对象的指针值,这里强转回 Parcel 指针
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
// 使用Parcel指针调用其 readInt32() 方法读取数据
return parcel->readInt32();
}
return 0;
}
static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jlong nativePtr)
{
// nativePtr 是 android_os_Parcel_create 返回的 Parcel 对象的指针值,这里强转回 Parcel 指针
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
size_t len;
// 使用Parcel指针调用其 readString16Inplace() 方法读取数据
const char16_t* str = parcel->readString16Inplace(&len);
if (str) {
return env->NewString(reinterpret_cast<const jchar*>(str), len);
}
return NULL;
}
return NULL;
}
由于代码量很多,这里只列出创建native层的Parcel对象和关于Int和String两种类型的写入和读取代码,所有的类型写入和读取方法都是首先通过传入的nativePtr变量强转成Parcel指针,此变量便是android_os_Parcel_create方法创建Parcel对象返回的指针值,接着使用Parcel指针来调用相应的写入和读取操作。
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:
// 将指针移动到偏移的位置(首地址+指针的偏移量),接着写入val到内存去
*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;
}
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;
}
int32_t Parcel::readInt32() const
{
return readAligned<int32_t>();
}
template<class T>
status_t Parcel::readAligned(T *pArg) const {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
// 判断内存是否足够
if ((mDataPos+sizeof(T)) <= mDataSize) {
// 将偏移指针赋给任意类型的数据指针
const void* data = mData+mDataPos;
// 更新指针的偏移量
mDataPos += sizeof(T);
// 返回数据
*pArg = *reinterpret_cast<const T*>(data);
return NO_ERROR;
} else {
return NOT_ENOUGH_DATA;
}
}
String16 Parcel::readString16() const
{
size_t len;
// 读取字符串
const char16_t* str = readString16Inplace(&len);
if (str) return String16(str, len);
return String16();
}
const char16_t* Parcel::readString16Inplace(size_t* outLen) const
{
int32_t size = readInt32();
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;
}
所以序列化和反序列化最终的写入和读取是在native层的Parcel.cpp中完成,在Parcel.cpp里会进行开辟一块连续的内存用来进行数据的缓存,其中内存的首地址是mData,偏移量是mDataPos。
当写入一个数据时,首先会将指针移动到对应的位置,即mData + mDataPos,然后再将数据写入内存,最后会重新计算mDataPos 的偏移量。到下次要写入数据时同理会将数据写入到内存的后面。
也是因为开辟的是一块连续的内存,所以在读取数据时只要保证跟写入数据的顺序一致,便能将内存中的数据读出。
8 总结
- 从使用上对比 Serializable 和 Parcelable,Serializable 会显得简单一些,两者都是实现不同的接口,但是 Serializable 可全自动序列化和反序列化,Parcelable 需要手动去 write 和 read 一系列方法才能完成序列化和反序列化。
- 从场景来考虑,Serializable 支持数据持久化存储到本地磁盘、网络传输等,Parcelable 则不支持。如果只在组件间或者跨进程组件间的传输数据的场景,虽然两者都是支持的。但是在内存使用和性能上 Parcelable 会优出 Serializable 很多,因为 Serializable 在序列化和反序列化过程中都需要较多的反射和IO操作,Parcelable 设计的目的就是为了提高这种场景下数据传输性能,因为其内部是通过Parcel来实现,Parcel?是一种可通过?IBinder?高性能传输数据和对象的容器,内部采用共享内存的方式实现用户空间和内核空间的数据交换,本质是?Native?层的共享内存。
- Parcelable的使用需要类继承Parcelable接口,并且必须重写describeContents 和 writeToParcel 两个方法和存在一个带Parcel类型参数的构造方法,以及必须声明一个非空的、名字必须是CREATOR的、类型是Parcelable.Creator<T>的静态变量。
- writeToParcel方法是实现序列化写操作的地方,而带Parcel参数的构造方法是实现反序列化读操作的地方。Parcel对象的写入和读取的顺序必须保持一致,否则会发生数值错误或者类型异常崩溃情况。
- 从IPC过程可知,当Client端发起跨进程请求时前,先调用Intent的writeToParcel方法,将Intent内存中的ArrayMap输出一个android.os.Parcel 类型的_data变量进行Parcelable的序列化。
- 从IPC过程可知,远程请求会通过系统底层封装后交由onTransact方法来处理,些时会接收android.os.Parcel 类型的_data变量,再创建新的Intent对象,Intent的构造函数会接收这个_data变量,并使用mParcelledData变量进行存储起来,当调用到Intent的getParcelableExtra或者getParcelable方法获取数据时,便是对内存中mParcelledData进行反序列化成ArrayMap。
|