一人一猫旅行记之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方法,所以只能到它的父类BaseBundle中寻找,结果如下:

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 "
+ Integer.toHexString(System.identityHashCode(this))
+ ": no parcelled data");
return;
}

if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
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 "
+ Integer.toHexString(System.identityHashCode(this)) + ": empty");
if (mMap == null) {
mMap = new ArrayMap<>(1);
} else {
mMap.erase();
}
mParcelledData = null;
return;
}

int N = parcelledData.readInt();
if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ ": reading " + N + " maps");
if (N < 0) {
return;
}
ArrayMap<String, Object> map = mMap;
if (map == null) {
map = new ArrayMap<>(N);
} else {
map.erase();
map.ensureCapacity(N);
}
try {
parcelledData.readArrayMapInternal(map, N, mClassLoader);
} catch (BadParcelableException e) {
if (sShouldDefuse) {
Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
map.erase();
} else {
throw e;
}
} finally {
mMap = map;
parcelledData.recycle();
mParcelledData = null;
}
if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ " final map: " + mMap);
}
}

从上面的代码我们可以看到一个Parcel对象mParcelledData,从代码看来是对该对象进行处理,实际上就是将Parcel数据迁移至mMap对象中。这样就可以保证我们从mMap中获取Bundle携带的数据。

@Nullable
public String getString(@Nullable String key) {
unparcel();
final Object o = mMap.get(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 = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;

我们回到Bundle.java看一下CREATOR

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

@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) {
if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
return null;
}

final Bundle bundle = new Bundle(this, length);
if (loader != null) {
bundle.setClassLoader(loader);
}
return bundle;
}

从Bundle的构造函数继续阅读代码

BaseBundle(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);

} else if (length == 0) {
// Empty Bundle or end of data.
mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
return;
}

final int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ Integer.toHexString(magic));
}

// Advance within this Parcel
int offset = parcel.dataPosition();
parcel.setDataPosition(MathUtils.addOrThrow(offset, length));

Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.appendFrom(parcel, offset, length);
if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this))
+ ": " + length + " bundle bytes starting at " + offset);
p.setDataPosition(0);

mParcelledData = p;
}

所以我们也可以知道mParcelledData实际就是传过来的Bundle序列化后的数据

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

一人一猫旅行记之Intent传递数据原理

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 一人一猫旅行记之Intent传递数据原理
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏