Android Intent传递Parcelable和Serializable对象原理分析

Android Intent传递Parcelable和Serializable对象原理分析

  当我们需要打开一个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<Pen> CREATOR = new Creator<Pen>() {
        @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.putSerializablemExtras.putParcelable,只要分析一个方法,另外的一个也就清楚了,所以后面只跟踪分析Parcelable,最后在看Serializable的实现。

IntentmExtras是一个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的实现类ComtextImplstartActivity方法,如下:

//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父类BaseBundlewriteToParcelInner方法

//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<String, Object> 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; i<N; i++) {
        if (DEBUG_ARRAY_MAP) startPos = dataPosition();
        writeString(val.keyAt(i));    //#1
        writeValue(val.valueAt(i));    //#2
       //...
    }
}

这个方法主要调用了#1#2两行代码,就是将ArrayMap<String, Object>类型的实例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强制转换为ParcelableSerializable接口,将ParcelableSerializable对象写入到当前的对象里面。

//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> T readTypedObject(Parcelable.Creator<T> 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<Pen> CREATOR = new Creator<Pen>() {
        @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用。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值