序列化Parcelable与Serializable

栏目: IOS · Android · 发布时间: 4年前

内容简介:主要是由于有以下几个疑问:1、为什么Android里面Activity之间传值, Parcelable比Serializable效率要高? 2、Activity之间通过Intent传值, 大小为什么会有限制? 限制在多少?关于Activity启动, 其实都知道, 最终会通过ActivityManagerProxy.startActivity然后将消息发送给system_server进程, 然后直接进入到AMP.startActivity方法内部;

主要是由于有以下几个疑问:

1、为什么Android里面Activity之间传值, Parcelable比Serializable效率要高? 2、Activity之间通过Intent传值, 大小为什么会有限制? 限制在多少?

关于Activity启动, 其实都知道, 最终会通过ActivityManagerProxy.startActivity然后将消息发送给system_server进程, 然后直接进入到AMP.startActivity方法内部;

ActivityManagerProxy.startActivity

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(callingPackage);
    // intent将携带的数据写入到Parcel中; 
    intent.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(resultTo);
    data.writeString(resultWho);
    data.writeInt(requestCode);
    data.writeInt(startFlags);
    if (profilerInfo != null) {
        data.writeInt(1);
        profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    } else {
        data.writeInt(0);
    }
    // mRemote实际指向的是BinderProxy对象
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
    ...
    return result;
}
复制代码

一、关于Parcelable与Serializable

1.1 Intent.writeToParcel

public void writeToParcel(Parcel out, int flags) {
    ...
    // intent.putXXX最终都是将数据写入到mExtras中, 现在又将mExtras数据写入到Parcel中;
    out.writeBundle(mExtras);
}
复制代码

1.2 Parcel.writeBundle

public final void writeBundle(Bundle val) {
    val.writeToParcel(this, 0);
}
复制代码

1.3 Bundle.writeToParcel

@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);
    }
}
void writeToParcelInner(Parcel parcel, int flags) {
    ...
    // map数据被写入到Parcel中;
    parcel.writeArrayMapInternal(map);
}
复制代码

1.4 Parcel.writeArrayMapInternal

void writeArrayMapInternal(ArrayMap<String, Object> val) {
    final int N = val.size();
    writeInt(N);
    int startPos;
    // 遍历val, 将写入数据到parcel中
    for (int i=0; i<N; i++) {
        writeString(val.keyAt(i));
        writeValue(val.valueAt(i));
    }
}
复制代码

1.5 Parcel.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) {
        writeInt(VAL_BUNDLE);
        writeBundle((Bundle) v);
    } else if (v instanceof PersistableBundle) {
        writeInt(VAL_PERSISTABLEBUNDLE);
        writePersistableBundle((PersistableBundle) v);
    } else if (v instanceof Parcelable) {// Parcelable类型
        writeInt(VAL_PARCELABLE);
        writeParcelable((Parcelable) v, 0);
    } 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) {
        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) {// Serializable类型
            // Must be last
            writeInt(VAL_SERIALIZABLE);
            writeSerializable((Serializable) v);
        } 
    }
}
复制代码

  1、从writeValue其实可以很直观的看出来, Parcel在进行写数据时, 除了支持基本数据类型及其数组, 还支持三种引用数据类型: String及其数组, 实现了Parcelable的类及其数组, 以及实现了Serializable的类.   2、而当V instanceof Parcelable时, 继续调用writeParcelable对V进行序列化数据读写操作.   3、当V instanceof Serializable时, 通过writeSerializable进行序列化数据读写操作;

1.5.1 Parcel.writeSerializable

public final void writeSerializable(Serializable s) {
    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);
    }
}
复制代码

  1、从代码可以很直观的看出, 当V instanceof Serializable时, 会先将数据转换成流数据, 然后再进行数据传输, 然后有一个问题, 如果使用Intent传输Serializable类型的数据, 输出方输出的对象与输入方接收到的数据是同一个吗?

public class B implements Serializable {
}
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = new Intent(this, TestUi.class);
        B b = new B();
        Log.v("AndroidTest", "b:" + b);
        intent.putExtra("B", b);
        startActivity(intent);
    }
}
public class TestUi extends Activity {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Serializable b = getIntent().getSerializableExtra("B");
        Log.v("AndroidTest", "b:" + b);
    }
}

打印结果如下:
06-24 12:36:24.648 b:androidtest.myapplication.B@37b040c1
06-24 12:36:24.674 b:androidtest.myapplication.B@2a0ffc9f
复制代码

总结: 当v instanceof Serializable时, 进程间通信传值时, 首先会将v转换为IO流数据, 然后再进行数据传输操作, 因为Parceable内部只支持基本数据类型及其数组, 以及String类型, 所以v instanceof Parcelable时, 直接进行值的传输. 这样就是为什么进行间通信Parceable效率要比Serializable效率高.

二、关于Intent传值大小限制的问题

ActivityManagerProxy.startActivity

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(callingPackage);
    // intent将携带的数据写入到Parcel中; 
    intent.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(resultTo);
    data.writeString(resultWho);
    data.writeInt(requestCode);
    data.writeInt(startFlags);
    if (profilerInfo != null) {
        data.writeInt(1);
        profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    } else {
        data.writeInt(0);
    }
    // mRemote实际指向的是BinderProxy对象
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
    ...
    return result;
}
复制代码

mRemote实际指向的是BinderProxy

BinderProxy.transact

public class Binder.BinderProxy {
    public boolean transact(int code, Parcel data, Parcel reply, int flags) {
        // Activity启动时, Intent携带的数据最终被转化到Parcel中, 这里检测data的大小
        // 也就是检测Intent携带的数据的大小;
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
        final boolean tracingEnabled = Binder.isTracingEnabled();
        return transactNative(code, data, reply, flags);
    }
}
public class Binder {
    static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
        // 大小限制在800kb
        if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {
            // Trying to send > 800k, this is way too much
            StringBuilder sb = new StringBuilder();
            sb.append(msg);
            sb.append(": on ");
            sb.append(obj);
            sb.append(" calling ");
            sb.append(code);
            sb.append(" size ");
            sb.append(parcel.dataSize());
            sb.append(" (data: ");
            parcel.setDataPosition(0);
            sb.append(parcel.readInt());
            sb.append(", ");
            sb.append(parcel.readInt());
            sb.append(", ");
            sb.append(parcel.readInt());
            sb.append(")");
            Slog.wtfStack(TAG, sb.toString());
        }
    }
}
复制代码

上面代码并没有做什么限制, 仅仅是从应用层角度进行提醒, 传输的数据大小不能超过800kb, 真正的大小限制是在native层, 流程比较复杂, 所以关于Intent传值大小限制, 这里仅仅记住结论.


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入理解Nginx(第2版)

深入理解Nginx(第2版)

陶辉 / 机械工业出版社 / 2016-2 / 99.00元

本书致力于说明开发Nginx模块的必备知识,第1版发行以后,深受广大读者的喜爱.然而由于Ng,nx功能繁多且性能强大,以致必须了解的基本技能也很庞杂,而第1版成书匆忙,缺失了几个进阶的技巧描述,因此第2版在此基础上进行了完善。 书中首先通过介绍官方Nginx的基本用法和配置规则,帮助读者了解一般Nginx模块的用法,然后重点介绍了女口何开发HTTP模块(含HTTP过滤模块)来得到定制化的Ng......一起来看看 《深入理解Nginx(第2版)》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具