内容简介:主要是由于有以下几个疑问: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传值大小限制, 这里仅仅记住结论.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux内核完全剖析
赵炯 / 机械工业出版社 / 2006-1 / 79.00元
本书对早期Linux操作系统内核全部代友文件进行了详细的剖析,旨在让读者在尽量短的时间内对Linux的工作机理获得全面而深刻的理解,为进一步学习和研究Linux系统打下坚实的基础。虽然选择的版本较低,但该内核已能够正常编译运行,并且其中已包括了Linux工作原理的精髓。书中首先以Linux源代码版本的变迁为主线,简要介绍了Lin-ux系统的发展历史,同时着重说明了各个内核版本之间的主要区别和改进方......一起来看看 《Linux内核完全剖析》 这本书的介绍吧!