安卓提供了Intent机制来实现应用间的通讯,能够在Activity之间、Service、BroadCast中传递数据。提起Intent,咱们最熟悉的可能就是在启动Activity的时候携带数据,使用很是简单:java
Intent intent = new Intent(MainActivity.this,SecondActivity.class); intent.putExtra("param1","我是参数1"); startActivity(intent);
在新的Activity,也就是Activity中获取数据也是很是的简单:web
String param1 = getIntent().getStringExtra("param1");
咱们能够看到在传值的时候,调用了Intent的putExtra方法,咱们查看Intent的源码,发现Intent中定义了许多的putExtra方法,以我们的上面的调用为例,其实是调用了以下的方法:app
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中寻找,结果以下:ide
ArrayMap<String, Object> mMap = null; <-省略部分代码-> public void putString(@Nullable String key, @Nullable String value) { unparcel(); mMap.put(key, value); }
咱们接着看看unparcel这个方法svg
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函数,咱们能够看到以下一段代码:ui
Bundle options = data.readInt() != 0 ? Bundle.CREATOR.createFromParcel(data) : null;
咱们回到Bundle.java看一下CREATORthis
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
继续往下走的话,咱们会走到以下方法:code
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的构造函数继续阅读代码xml
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序列化后的数据