当我们需要打开一个Activity
的时候,经常使用Intent
去传递一些数据给将要打开的Activity
。这些数据类型中经常会包含类类型,但是不能什么类都可以通过Intent
传递的,必须是实现了Parcelable
或者Serializable
接口才行。如:
实现Serializeble
例子
public class Person implements Serializable{
private static final long serialVersionUID = 7382351359868556980L;
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
实现Parcelable
例子
public class Pen implements Parcelable{
private String color;
private int size;
protected Pen(Parcel in) {
color = in.readString();
size = in.readInt();
}
public static final Creator CREATOR = new Creator() {
@Override
public Pen createFromParcel(Parcel in) {
return new Pen(in);
}
@Override
public Pen[] newArray(int size) {
return new Pen[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(color);
dest.writeInt(size);
}
}
那么问题来了,那为什么需要实现这两个接口呢?实现的接口又是怎么被调用的呢?
启动一个Activity
并且传递对象给启动的Activity
Intent intent = new Intent(getActivity(), NewActivity.class);
intent.putExtra("person", new Person()); // #1
intent.putExtra("person", new Pen()); // #2
startActivity(intent);
Intent.putExtra()
有很多个重写的方法,#1
处会调用
//Intent.java
public Intent putExtra(String name, Serializable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putSerializable(name, value);
return this;
}
#2
处会调用
//Intent.java
public Intent putExtra(String name, Parcelable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putParcelable(name, value);
return this;
}
可以看到两个方法其实内容差不多,分别主要调用了mExtras.putSerializable
和mExtras.putParcelable
,只要分析一个方法,另外的一个也就清楚了,所以后面只跟踪分析Parcelable
,最后在看Serializable
的实现。
在Intent
中mExtras
是一个Bundle
类,接着分析mExtras.putParcelable()
方法
//Bunder.java
public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
unparcel(); //初始化容器
mMap.put(key, value); //将 key 和 value 存放在 ArrayMap 成员变量中
mFdsKnown = false;
}
将对象值保存在Intent
后,接着会调用Activity.startActivity( Intent )
方法,将Intent
的保存的值传递给打开的Activity
去。我们知道调用Activity.startActivity
方法会调用Context
的实现类ComtextImpl
的startActivity
方法,如下:
//ContextImpl.java
@Override
public void startActivity(Intent intent) {
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
}
上面的方法主要调用了 mMainThread.getInstrumentation().execStartActivity
,这个方法最终会调用ActivityManagerService
的代理类ActivityManagerProxy
类的startActivity()
。如果不清楚这一过程的可以参考Android应用程序启动过程源代码分析,这里不是我们的重点。
//ActivityManagerProxy.java
public int startActivity(IApplicationThread caller, Intent intent,
String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
IBinder resultTo, String resultWho,
int requestCode, boolean onlyIfNeeded,
boolean debug) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
intent.writeToParcel(data, 0); //#1
data.writeString(resolvedType);
data.writeTypedArray(grantedUriPermissions, 0);
data.writeInt(grantedMode);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(onlyIfNeeded ? 1 : 0);
data.writeInt(debug ? 1 : 0);
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
这个方法的参数Intent
还是我们自己new
出来的那个Intent
对象。这个有关这个参数的就只有#1
intent.writeToParcel(data, 0);
具体调用如下:
//Intent.java
public void writeToParcel(Parcel out, int flags) {
out.writeString(mAction);
Uri.writeToParcel(out, mData);
out.writeString(mType);
out.writeInt(mFlags);
out.writeString(mPackage);
//...
out.writeInt(mContentUserHint);
out.writeBundle(mExtras); //#1 将mExtras里面的内容写入out对象里
}
可以看到最后#1
使用到了mExtras
,这个参数是我们前面提到了Bundle
类型的Intent
成员变量,当时我们的对象就是保存在这个里面的。接着玩下看
//Parcel.java
public final void writeBundle(Bundle val) {
if (val == null) {
writeInt(-1);
return;
}
val.writeToParcel(this, 0);//#1
}
#1
调用了Bundle.writeToParcel
,将Bundle
里面的内容写入out对象里
//Bundle.java
/**
* Writes the Bundle contents to a Parcel, typically in order for
* it to be passed through an IBinder connection.
* @param parcel The parcel to copy this bundle to.
*/
@Override
public void writeToParcel(Parcel parcel, int flags) {
final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
try {
super.writeToParcelInner(parcel, flags); //#1
} finally {
parcel.restoreAllowFds(oldAllowFds);
}
}
上面的方法又会调用super.writeToParcelInner
,即调用Bundle
父类BaseBundle
的writeToParcelInner
方法
//BaseBundle.java
/**
* Writes the Bundle contents to a Parcel, typically in order for
* it to be passed through an IBinder connection.
* @param parcel The parcel to copy this bundle to.
*/
void writeToParcelInner(Parcel parcel, int flags) {
// Keep implementation in sync with writeToParcel() in
// frameworks/native/libs/binder/PersistableBundle.cpp.
final Parcel parcelledData;
synchronized (this) {
parcelledData = mParcelledData;
}
if (parcelledData != null) {
if (isEmptyParcel()) {
parcel.writeInt(0);
} else {
int length = parcelledData.dataSize();
parcel.writeInt(length);
parcel.writeInt(BUNDLE_MAGIC);
parcel.appendFrom(parcelledData, 0, length);
}
} else {
// Special case for empty bundles.
if (mMap == null || mMap.size() <= 0) {
parcel.writeInt(0);
return;
}
int lengthPos = parcel.dataPosition();
parcel.writeInt(-1); // dummy, will hold length
parcel.writeInt(BUNDLE_MAGIC);
int startPos = parcel.dataPosition();
parcel.writeArrayMapInternal(mMap); //#1
int endPos = parcel.dataPosition();
// Backpatch length
parcel.setDataPosition(lengthPos);
int length = endPos - startPos;
parcel.writeInt(length);
parcel.setDataPosition(endPos);
}
}
可以看到这个方法会调用#1
parcel.writeArrayMapInternal(mMap);
这里的mMap
很眼熟,我们之前的就是把将要传递的对象保存以key/value
的形式保存在这个里面的。接着往下看
//Parcel.java
/**
* Flatten an ArrayMap into the parcel at the current dataPosition(),
* growing dataCapacity() if needed. The Map keys must be String objects.
*/
void writeArrayMapInternal(ArrayMap val) {
if (val == null) {
writeInt(-1);
return;
}
// Keep the format of this Parcel in sync with writeToParcelInner() in
// frameworks/native/libs/binder/PersistableBundle.cpp.
final int N = val.size();
writeInt(N);
//...
int startPos;
for (int i=0; iif (DEBUG_ARRAY_MAP) startPos = dataPosition();
writeString(val.keyAt(i)); //#1
writeValue(val.valueAt(i)); //#2
//...
}
}
这个方法主要调用了#1
,#2
两行代码,就是将ArrayMap
类型的实例val
所保存的数据一一取出来然后依次保存在当前的Parcel
对象里面。最重要的是#2
writeValue(val.valueAt(i));
,这里就是要取出我们保存在Intent
里面的Parcelable
或者Serializable
对象了。接着往下看
//Parcel.java
public final void writeValue(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) {
// IMPOTANT: cases for classes that implement Parcelable must
// come before the Parcelable case, so that their specific VAL_*
// types will be written.
writeInt(VAL_PARCELABLE);
writeParcelable((Parcelable) v, 0); //#1
} else if (v instanceof Short) {
writeInt(VAL_SHORT);
writeInt(((Short) v).intValue());
} else if (v instanceof Long) {
writeInt(VAL_LONG);
writeLong((Long) v);
} else if (v instanceof Float) {
writeInt(VAL_FLOAT);
writeFloat((Float) v);
} else if (v instanceof Double) {
writeInt(VAL_DOUBLE);
writeDouble((Double) v);
} else if (v instanceof Boolean) {
writeInt(VAL_BOOLEAN);
writeInt((Boolean) v ? 1 : 0);
} else if (v instanceof CharSequence) {
// Must be after String
writeInt(VAL_CHARSEQUENCE);
writeCharSequence((CharSequence) v);
} else if (v instanceof List) {
writeInt(VAL_LIST);
writeList((List) v);
} else if (v instanceof SparseArray) {
writeInt(VAL_SPARSEARRAY);
writeSparseArray((SparseArray) v);
} else if (v instanceof boolean[]) {
writeInt(VAL_BOOLEANARRAY);
writeBooleanArray((boolean[]) v);
} else if (v instanceof byte[]) {
writeInt(VAL_BYTEARRAY);
writeByteArray((byte[]) v);
} else if (v instanceof String[]) {
writeInt(VAL_STRINGARRAY);
writeStringArray((String[]) v);
} else if (v instanceof CharSequence[]) {
// Must be after String[] and before Object[]
writeInt(VAL_CHARSEQUENCEARRAY);
writeCharSequenceArray((CharSequence[]) v);
} else if (v instanceof IBinder) {
writeInt(VAL_IBINDER);
writeStrongBinder((IBinder) v);
} else if (v instanceof Parcelable[]) {
writeInt(VAL_PARCELABLEARRAY);
writeParcelableArray((Parcelable[]) v, 0);
} else if (v instanceof int[]) {
writeInt(VAL_INTARRAY);
writeIntArray((int[]) v);
} else if (v instanceof long[]) {
writeInt(VAL_LONGARRAY);
writeLongArray((long[]) v);
} else if (v instanceof Byte) {
writeInt(VAL_BYTE);
writeInt((Byte) v);
} else if (v instanceof Size) {
writeInt(VAL_SIZE);
writeSize((Size) v);
} else if (v instanceof SizeF) {
writeInt(VAL_SIZEF);
writeSizeF((SizeF) v);
} else if (v instanceof double[]) {
writeInt(VAL_DOUBLEARRAY);
writeDoubleArray((double[]) v);
} else {
Class> clazz = v.getClass();
if (clazz.isArray() && clazz.getComponentType() == Object.class) {
// Only pure Object[] are written here, Other arrays of non-primitive types are
// handled by serialization as this does not record the component type.
writeInt(VAL_OBJECTARRAY);
writeArray((Object[]) v);
} else if (v instanceof Serializable) {
// Must be last
writeInt(VAL_SERIALIZABLE);
writeSerializable((Serializable) v); //#2
} else {
throw new RuntimeException("Parcel: unable to marshal value " + v);
}
}
}
注意查看#1
,#2
两处代码,这里分别先将Object
类型v
强制转换为Parcelable
和Serializable
接口,将Parcelable
和Serializable
对象写入到当前的对象里面。
//Parcel.java
public final void writeParcelable(Parcelable p, int parcelableFlags) {
if (p == null) {
writeString(null);
return;
}
writeParcelableCreator(p); //保存类名
p.writeToParcel(this, parcelableFlags); //#1
}
#1
最终调用Parcelable
接口的writeToParcel
方法,这里就会调用我们前面Pen
类实现的writeToParcel
方法,即:
//Pen.java
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(color);
dest.writeInt(size);
}
将当前类各个成员的值写入到dest
对象里面。
同样的writeSerializable
方法最终会调用Java
自带的序列化类ObjectOutputStream
来序列话Serializable
对象,将其转化为字节数组保存到Parcel
里面。
/**
* Write a generic serializable object in to a Parcel. It is strongly
* recommended that this method be avoided, since the serialization
* overhead is extremely large, and this approach will be much slower than
* using the other approaches to writing data in to a Parcel.
*/
public final void writeSerializable(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);
}
}
到这里,系统将需要传递给要打开的Activity
的数据打包到Parcel
里面去了,接着会将这个包裹传递给Binder
驱动。
当一个Activity
构造出来之后又会调用
//Parcel.java
public final T readTypedObject(Parcelable.Creator c) {
if (readInt() != 0) {
return c.createFromParcel(this);
} else {
return null;
}
}
接着调用到Pen的CREATOR对象的createFromParcel
,生成一个对象:
//Pen.java
protected Pen(Parcel in) {
color = in.readString();
size = in.readInt();
}
public static final Creator CREATOR = new Creator() {
@Override
public Pen createFromParcel(Parcel in) {
return new Pen(in);
}
@Override
public Pen[] newArray(int size) {
return new Pen[size];
}
};
最终组装的这个对象会传递给Activity
.
总的来说,两个Activity
通过Intent
传递一个对象的过程,就是将对象每一个成员变量的值保存到Parcel
中,传递给Binder
驱动,然后再将Parcel
组装起来,形成一个对象,然后提供给另一个Activity
用。