大家都知道,要想在Intent里面传递一些非基本类型的数据,有两种方式,一种实现Parcelable,另一种是实现Serializable接口。

今天先不说Serializable 接口,只说Parcelable。

我们知道,Parcelable 只是一个接口,里面有几个关键方法:

writeToParcel

   /**     * Flatten this object in to a Parcel.     *      * @param dest The Parcel in which the object should be written.     * @param flags Additional flags about how the object should be written.     * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.     */    public void writeToParcel(Parcel dest, @WriteFlags int flags);

这个方法会让你把当前你需要保存的数据,写进Parcel 里。flags 可以写0 ,也可以写PARCELABLE_WRITE_RETURN_VALUE。这两个什么区别呢?后面再说。

这个里面,你需要调用传给你的Parcel 对象dest,把你需要的数据传递进去。Such as:

 *     public void writeToParcel(Parcel out, int flags) { *         out.writeInt(mData); *     }

同时需要实现一个Creator, 用来恢复对象,如果没有实现这个Creator,那么恢复的时候,会报错。

    /**     * Interface that must be implemented and provided as a public CREATOR     * field that generates instances of your Parcelable class from a Parcel.     */    public interface Creator {        /**         * Create a new instance of the Parcelable class, instantiating it         * from the given Parcel whose data had previously been written by         * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.         *          * @param source The Parcel to read the object's data from.         * @return Returns a new instance of the Parcelable class.         */        public T createFromParcel(Parcel source);                /**         * Create a new array of the Parcelable class.         *          * @param size Size of the array.         * @return Returns an array of the Parcelable class, with every entry         * initialized to null.         */        public T[] newArray(int size);    }

createFromParcel(Parcel source);

这个方法是,当你恢复对象的时候,会把source 传递给你,让你去读取。

官方给的例子:

 * *     public static final Parcelable.Creator MyParcelable> CREATOR *             = new Parcelable.Creator<MyParcelable>() { *         public MyParcelable createFromParcel(Parcel in) { *             return new MyParcelable(in); *         } * *         public MyParcelable[] newArray(int size) { *             return new MyParcelable[size]; *         } *     }; *      *     private MyParcelable(Parcel in) { *         mData = in.readInt(); *     }

那么为什么这几个方法就可以把一个对象放到intent 里面呢?然后还可以取出来?

我们看下源码:

  /**     * Add extended data to the intent.  The name must include a package     * prefix, for example the app com.android.contacts would use names     * like "com.android.contacts.ShowAll".     *     * @param name The name of the extra data, with package prefix.     * @param value The Parcelable data value.     *     * @return Returns the same Intent object, for chaining multiple calls     * into a single statement.     *     * @see #putExtras     * @see #removeExtra     * @see #getParcelableExtra(String)     */    public @NonNull Intent putExtra(String name, Parcelable value) {        if (mExtras == null) {            mExtras = new Bundle();        }        mExtras.putParcelable(name, value);        return this;    }

我们可以看到,其实是放到了mExtras 里面。

    private Bundle mExtras;

他其实是个Bundle.
Bundle 其实也是实现了Parcelable 接口

public final class Bundle extends BaseBundle implements Cloneable, Parcelable {

我们看下Bundle putParcelable 的实现:

    /**     * Inserts a Parcelable value into the mapping of this Bundle, replacing     * any existing value for the given key.  Either key or value may be null.     *     * @param key a String, or null     * @param value a Parcelable object, or null     */    public void putParcelable(@Nullable String key, @Nullable Parcelable value) {        unparcel();        mMap.put(key, value);        mFlags &= ~FLAG_HAS_FDS_KNOWN;    }

进入unparcel();

    /**     * If the underlying data are stored as a Parcel, unparcel them     * using the currently assigned class loader.     */    /* package */ void unparcel() {        synchronized (this) {            final Parcel source = mParcelledData;            if (source != null) {                initializeFromParcelLocked(source, /*recycleParcel=*/ true);            } else {                if (DEBUG) {                    Log.d(TAG, "unparcel "                            + Integer.toHexString(System.identityHashCode(this))                            + ": no parcelled data");                }            }        }    }

正常的情况下,mParcelledData是null 的。我们可以看到,其实这里面只是简单的put 进去。

ok ,传递数据的时候,Bundle 是要传递过去的,肯定会调用writeToParcel。

  /**     * 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);        } finally {            parcel.restoreAllowFds(oldAllowFds);        }    }

调用了 super.writeToParcelInner(parcel, flags);
我们看下BaseBundle 的 writeToParcelInner(parcel, flags);:

    /**     * 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) {        // If the parcel has a read-write helper, we can't just copy the blob, so unparcel it first.        if (parcel.hasReadWriteHelper()) {            unparcel();        }        // Keep implementation in sync with writeToParcel() in        // frameworks/native/libs/binder/PersistableBundle.cpp.        final ArrayMap 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(BUNDLE_MAGIC);                    parcel.appendFrom(mParcelledData, 0, length);                }                return;            }            map = mMap;        }        // Special case for empty bundles.        if (map == null || map.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(map);        int endPos = parcel.dataPosition();        // Backpatch length        parcel.setDataPosition(lengthPos);        int length = endPos - startPos;        parcel.writeInt(length);        parcel.setDataPosition(endPos);    }

里面写了一堆,关键是 parcel.writeArrayMapInternal(map); 这句把map 写到了parcel 里面。

我们看下Parcel 的writeArrayMapInternal方法:

    /**     * Flatten an ArrayMap into the parcel at the current dataPosition(),     * growing dataCapacity() if needed.  The Map keys must be String objects.     */    /* package */ 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);        if (DEBUG_ARRAY_MAP) {            RuntimeException here =  new RuntimeException("here");            here.fillInStackTrace();            Log.d(TAG, "Writing " + N + " ArrayMap entries", here);        }        int startPos;        for (int i=0; i

首先写了长度,然后写k,写 value。我们看下这里的writeValue方法

    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);        } else if (v instanceof Short) {            writeInt(VAL_SHORT);            writeInt(((Short) v).intValue());        }....    }

如果发现写的是Parcelable 的话,就writeParcelable

    public final void writeParcelable(Parcelable p, int parcelableFlags) {        if (p == null) {            writeString(null);            return;        }        writeParcelableCreator(p);        p.writeToParcel(this, parcelableFlags);    }    public final void writeParcelableCreator(Parcelable p) {        String name = p.getClass().getName();        writeString(name);    }

这里首先会写一下Parcelable 对象的类名字,然后调用了Parcelable 对象的writeToParcel。也就是自己实现的方法,就会把我们想要传递的数据写到Parcel 里面去。

OK ,这样,Parcelable 接口的writeToParcel 方法就被调用了。

我们再看下Parcel 的readFromParcel

    /**     * Reads the Parcel contents into this Bundle, typically in order for     * it to be passed through an IBinder connection.     * @param parcel The parcel to overwrite this bundle from.     */    public void readFromParcel(Parcel parcel) {        super.readFromParcelInner(parcel);        mFlags = FLAG_ALLOW_FDS;        maybePrefillHasFds();    }
super.readFromParcelInner(parcel);
    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));        }        if (parcel.hasReadWriteHelper()) {            // If the parcel has a read-write helper, then we can't lazily-unparcel it, so just            // unparcel right away.            synchronized (this) {                initializeFromParcelLocked(parcel, /*recycleParcel=*/ false);            }            return;        }        // 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);        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;    }

很简单,把当前的mParcelledData 赋了值。

我们调用getParcelable 的时候,会首先 unparcel();

    public  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;        }    }
    /* package */ void unparcel() {        synchronized (this) {            final Parcel source = mParcelledData;            if (source != null) {                initializeFromParcelLocked(source, /*recycleParcel=*/ true);            } else {                if (DEBUG) {                    Log.d(TAG, "unparcel "                            + Integer.toHexString(System.identityHashCode(this))                            + ": no parcelled data");                }            }        }    }
private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel) {        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(parcelledData)) {            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;        }        final int count = parcelledData.readInt();        if (DEBUG) {            Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))                    + ": reading " + count + " maps");        }        if (count < 0) {            return;        }        ArrayMap map = mMap;        if (map == null) {            map = new ArrayMap<>(count);        } else {            map.erase();            map.ensureCapacity(count);        }        try {            parcelledData.readArrayMapInternal(map, count, 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;            if (recycleParcel) {                recycleParcel(parcelledData);            }            mParcelledData = null;        }        if (DEBUG) {            Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))                    + " final map: " + mMap);        }    }

parcelledData.readArrayMapInternal(map, count, mClassLoader);
最终调用了Parcel 类的readArrayMapInternal

    /* package */ void readArrayMapInternal(ArrayMap outVal, int N,        ClassLoader loader) {        if (DEBUG_ARRAY_MAP) {            RuntimeException here =  new RuntimeException("here");            here.fillInStackTrace();            Log.d(TAG, "Reading " + N + " ArrayMap entries", here);        }        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();    }

调用了readValue

public final Object readValue(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:            return readParcelable(loader);    .......    }

readParcelable(loader);

    public final  T readParcelable(ClassLoader loader) {        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);        }        return (T) creator.createFromParcel(this);    }
 public final Parcelable.Creator<?> readParcelableCreator(ClassLoader loader) {        String name = readString();        if (name == null) {            return null;        }        Parcelable.Creator<?> creator;        synchronized (mCreators) {            HashMap> map = mCreators.get(loader);            if (map == null) {                map = new HashMap<>();                mCreators.put(loader, map);            }            creator = map.get(name);            if (creator == null) {                try {                    // If loader == null, explicitly emulate Class.forName(String) "caller                    // classloader" behavior.                    ClassLoader parcelableClassLoader =                            (loader == null ? getClass().getClassLoader() : loader);                    // Avoid initializing the Parcelable class until we know it implements                    // Parcelable and has the necessary CREATOR field. http://b/1171613.                    Class<?> parcelableClass = Class.forName(name, false /* initialize */,                            parcelableClassLoader);                    if (!Parcelable.class.isAssignableFrom(parcelableClass)) {                        throw new BadParcelableException("Parcelable protocol requires that the "                                + "class implements Parcelable");                    }                    Field f = parcelableClass.getField("CREATOR");                    if ((f.getModifiers() & Modifier.STATIC) == 0) {                        throw new BadParcelableException("Parcelable protocol requires "                                + "the CREATOR object to be static on class " + name);                    }                    Class<?> creatorType = f.getType();                    if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {                        // Fail before calling Field.get(), not after, to avoid initializing                        // parcelableClass unnecessarily.                        throw new BadParcelableException("Parcelable protocol requires a "                                + "Parcelable.Creator object called "                                + "CREATOR on class " + name);                    }                    creator = (Parcelable.Creator<?>) f.get(null);                }                catch (IllegalAccessException e) {                    Log.e(TAG, "Illegal access when unmarshalling: " + name, e);                    throw new BadParcelableException(                            "IllegalAccessException when unmarshalling: " + name);                }                catch (ClassNotFoundException e) {                    Log.e(TAG, "Class not found when unmarshalling: " + name, e);                    throw new BadParcelableException(                            "ClassNotFoundException when unmarshalling: " + name);                }                catch (NoSuchFieldException e) {                    throw new BadParcelableException("Parcelable protocol requires a "                            + "Parcelable.Creator object called "                            + "CREATOR on class " + name);                }                if (creator == null) {                    throw new BadParcelableException("Parcelable protocol requires a "                            + "non-null Parcelable.Creator object called "                            + "CREATOR on class " + name);                }                map.put(name, creator);            }        }        return creator;    }

里面会加载你的Parcel 类,如果发现没有creator 就会抛异常。等等,最终调用了你的类的createFromParcel。

ok ,整个流程到这里就结束了。Parcleable 接口的调用大家都明白了吧。

更多相关文章

  1. android应用程序最小化的处理方法
  2. Android新线程中更新主线程UI中的View方法汇总
  3. 彻底解决Android 应用方法数不能超过65536的问题
  4. android install faild insufficient storage错误的解决方法
  5. [Android]ListView & ViewPager & GridView 常见问题解决方法
  6. Android中数据存储的几种方法
  7. Android退出时关闭所有Activity的方法
  8. Android中判断Intent是否存在的方法
  9. Android 子线程修改UI方法对比

随机推荐

  1. 【ImageView】图片自适应及android:scale
  2. Android传感器的运用之ACCELEROMETER
  3. Androidの自定义对话框AlertDialog(一)
  4. Android快速生成MVP 模式代码
  5. Android(安卓)Drawable Resource学习(二)、
  6. Android : android 9.0 audio 接口分析
  7. Android Studio 之 AndroidManifest.xml
  8. android studio打包apk时遇见的一些问题
  9. Android(安卓)签名详解
  10. android:sharedUserId="android.uid.syst