⼀⼈⼀猫旅⾏记之Intent传递数据原理
安卓提供了Intent机制来实现应⽤间的通信,可以在Activity之间、Service、BroadCast中传递数据。提起Intent,我们最熟悉的可能就是在启动Activity的时候携带数据,使⽤⾮常简单:
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("param1","我是参数1");
startActivity(intent);
在新的Activity,也就是Activity中获取数据也是⾮常的简单:
String param1 = getIntent().getStringExtra("param1");
我们可以看到在传值的时候,调⽤了Intent的putExtra⽅法,我们查看Intent的源码,发现Intent中定义了许多的putExtra⽅法,以咱们的上⾯的调⽤为例,实际上是调⽤了如下的⽅法:
public Intent putExtra(String name, String value) {
if (mExtras == null) {
mExtras = new Bundle();
}
mExtras.putString(name, value);
return this;
欧盟的缩写}
从上⾯的代码我们可以明⽩,在Intent中定义了⼀个Bundle类型的变量mExtras,当调⽤Intent的putExtra时,会根据第⼆个参数类型的不同,调⽤Bundle的对应⽅法。我们跑到Bundle会惊喜的发现没有putString⽅法,所以只能到它的⽗类BaBundle中寻找,结果如下:
ArrayMap<String, Object> mMap = null;
<-省略部分代码->
public void putString(@Nullable String key, @Nullable String value) {
unparcel();
mMap.put(key, value);
}
我们接着看看unparcel这个⽅法
synchronized void unparcel() {
synchronized (this) {
final Parcel parcelledData = mParcelledData;
if (parcelledData == null) {
if (DEBUG) Log.d(TAG, "unparcel "
+ HexString(System.identityHashCode(this))
+ ": no parcelled data");
return;
}
if (LOG_DEFUSABLE && sShouldDefu && (mFlags & FLAG_DEFUSABLE) == 0) {liberty
Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
+ "clobber all data inside!", new Throwable());
英语四级报名}
if (isEmptyParcel()) {
if (DEBUG) Log.d(TAG, "unparcel "
+ HexString(System.identityHashCode(this)) + ": empty");
if (mMap == null) {
mMap = new ArrayMap<>(1);
} el {
}sabian
mParcelledData = null;
return;
}
int N = adInt();美国留学高中成绩单
if (DEBUG) Log.d(TAG, "unparcel " + HexString(System.identityHashCode(this))
+ ": reading " + N + " maps");
if (N < 0) {
return;
}
ArrayMap<String, Object> map = mMap;comfortably
if (map == null) {
map = new ArrayMap<>(N);
} el {
}
try {
} catch (BadParcelableException e) {
if (sShouldDefu) {
Log.w(TAG, "Failed to par Bundle, but defusing quietly", e);
} el {
throw e;
}
} finally {
mMap = map;
mParcelledData = null;
}
if (DEBUG) Log.d(TAG, "unparcel " + HexString(System.identityHashCode(this))
+ " final map: " + mMap);
}
}
从上⾯的代码我们可以看到⼀个Parcel对象mParcelledData,从代码看来是对该对象进⾏处理,实际上就是将Parcel数据迁移⾄mMap对象中。这样就可以保证我们从mMap中获取Bundle携带的数据。
@Nullable
public String getString(@Nullable String key) {
unparcel();
final Object o = (key);
try {
return (String) o;
} catch (ClassCastException e) {
typeWarning(key, o, "String", e);
return null;
}
}
也可以把unparcel这个⽅法看成⼀个预处理,就是把已经序列化的数据反序列化后放在mMap中,之后Bundle就可以通过key从mMap中读取数据。但是有⼀个问题,mParcelledData这个对象是从哪⾥来的呢?
我们以startActivity为例,最终会调⾛到ActivityManagerNative中的onTransact函数,我们可以看到如下⼀段代码:
Bundle options = adInt() != 0什么是townhou
ateFromParcel(data) : null;
我们回到Bundle.java看⼀下CREATOR
public static final Parcelable.Creator<Bundle> CREATOR =
new Parcelable.Creator<Bundle>() {
@Override
public Bundle createFromParcel(Parcel in) {
adBundle();
}
@Override
public Bundle[] newArray(int size) {
return new Bundle[size];
}
};
从上⾯这段代码,可以看出createFromParcel实际调⽤的是Parcel的readBundle
英文转换器继续往下⾛的话,我们会⾛到如下⽅法:
public final Bundle readBundle(ClassLoader loader) {
int length = readInt();
if (length < 0) {siggraph
if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
return null;
}
final Bundle bundle = new Bundle(this, length);
if (loader != null) {
bundle.tClassLoader(loader);
}
return bundle;
}
从Bundle的构造函数继续阅读代码
BaBundle(Parcel parcelledData, int length) {
readFromParcelInner(parcelledData, length);
}
private void readFromParcelInner(Parcel parcel, int length) {
if (length < 0) {
throw new RuntimeException("Bad length in parcel: " + length);
} el if (length == 0) {
/
/ Empty Bundle or end of data.
mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
return;
}
final int magic = adInt();
if (magic != BUNDLE_MAGIC) {
throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ HexString(magic));
}
// Advance within this Parcel
int offt = parcel.dataPosition();
parcel.tDataPosition(MathUtils.addOrThrow(offt, length));
Parcel p = Parcel.obtain();
p.tDataPosition(0);
p.appendFrom(parcel, offt, length);
if (DEBUG) Log.d(TAG, "Retrieving " + HexString(System.identityHashCode(this)) + ": " + length + " bundle bytes starting at " + offt);
p.tDataPosition(0);
mParcelledData = p;
毕竟英文
}
所以我们也可以知道mParcelledData实际就是传过来的Bundle序列化后的数据