Android源码之Parcel

Parcel的意思是“打包”。在Android中,Parcel的作用类似于Java中的serialize,即对象的序列化。Android系统定位为内存受限的设备,因此对性能要求更高,另外系统中采用了新的IPC机制,必然要求使用性能更出色的对象传输方式。在这样的环境下,Parcel被设计出来,其定位就是轻量级的高效的对象序列化和反序列化机制。

Parcel的最主要作用是在各个activity之间传递数据。Android开发中,很经常在各activity之间传递数据,而跟据Android的设计架构,即使同一个程序中的Activity都不一定运行在同一个进程中,所以处理数据传递时你不能老假设两个activity都运行于同一进程,那么只能按进程间传递数据来处理,使之具有最广泛的适应性。

Parcel的接口主要有以下几类:

一、Parcel的获取与释放

public static Parcel obtain() {
	final Parcel[] pool = sOwnedPool;
	synchronized (pool) {
		Parcel p;
		for (int i=0; i<POOL_SIZE; i++) {
			p = pool[i];
			if (p != null) {
				pool[i] = null;
				if (DEBUG_RECYCLE) {
					p.mStack = new RuntimeException();
				}
				return p;
			}
		}
	}
	return new Parcel(0);
}

public final void recycle() {
	if (DEBUG_RECYCLE) mStack = null;
	freeBuffer();
	final Parcel[] pool = mOwnObject != 0 ? sOwnedPool : sHolderPool;
	synchronized (pool) {
		for (int i=0; i<POOL_SIZE; i++) {
			if (pool[i] == null) {
				pool[i] = this;
				return;
			}
		}
	}
}

获取接口obtain是从一个已分配的Parcel池中取得一个Parcel,即sOwnedPool,其定义如下:

private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];

当使用完获得的Parcel后,最好使用recycle将其释放回池,以便下次使用,否则导致Parcel池无可分配资源而new新对象。幸运的是,eclipse会给出此类的警告提示。


二、Parcel内部指针的移动

public final native int dataSize();
public final native int dataAvail();
public final native int dataPosition();
public final native int dataCapacity();
public final native void setDataSize(int size);
public final native void setDataPosition(int pos);
public final native void setDataCapacity(int size);

由于Parcel的读写是直接在内存中的,所以这几个接口就是指示当前的读写指针,类似于Linux下的文件读写操作:

dataSize:返回当前内存块中总共的数据

dataPosition:返回当前读操作指针

dataAvail:返回当前可读的数据,即dataSize - dataPosition

dataCapacity:返回当前内存块的容量(在不重新分配内存的前提下),dataCapacity - dataSize即为可写入的数据量


三、数据读写类

1、序列化与反序列化

public final native byte[] marshall();
public final native void unmarshall(byte[] data, int offest, int length);

作用类似于序列化和反序列化。即将当前Parcel的数据序列化为byte数组,或者将byte数组反序列化到当前Parcel中。

注:unmarshall后,如果要读取数据,首先需要将文件指针移动到初始化位置,即setDataPosition(0)。


2、基本数据类型的读写

private native void writeNative(byte[] b, int offset, int len);
public final native void writeInt(int val);
public final native void writeLong(long val);
public final native void writeFloat(float val);
public final native void writeDouble(double val);
public final native void writeString(String val);
public final native void writeStrongBinder(IBinder val);
public final native void writeFileDescriptor(FileDescriptor val);

public final native int readInt();
public final native long readLong();
public final native float readFloat();
public final native double readDouble();
public final native String readString();
public final native IBinder readStrongBinder();

全部都是native方法,通过JNI来调用底层实现。其余类型的读写都是在基本数据类型的基础上得来的。如:

public final void writeByte(byte val) {
	writeInt(val);
}
public final byte readByte() {
	return (byte)(readInt() & 0xff);
}

可见,byte在Parcel中也占用四个字节。


3、Array类型的读写

Array类型的接口按类型来分,如boolean[]/char[]/int[]/float[]/double[]/String[],而每一种类型都包含三个接口:

public final void writeXXXArray(boolean[] val);

public final boolean[] createXXXArray();

public final void readXXXArray(boolean[] val);

以boolean类型为例:其源码如下:

public final void writeBooleanArray(boolean[] val) {
	if (val != null) {
		int N = val.length;
		writeInt(N);
		for (int i=0; i<N; i++) {
			writeInt(val[i] ? 1 : 0);
		}
	} else {
		writeInt(-1);
	}
}

public final boolean[] createBooleanArray() {
	int N = readInt();
	// >>2 as a fast divide-by-4 works in the create*Array() functions
	// because dataAvail() will never return a negative number.  4 is
	// the size of a stored boolean in the stream.
	if (N >= 0 && N <= (dataAvail() >> 2)) {
		boolean[] val = new boolean[N];
		for (int i=0; i<N; i++) {
			val[i] = readInt() != 0;
		}
		return val;
	} else {
		return null;
	}
}

public final void readBooleanArray(boolean[] val) {
	int N = readInt();
	if (N == val.length) {
		for (int i=0; i<N; i++) {
			val[i] = readInt() != 0;
		}
	} else {
		throw new RuntimeException("bad array lengths");
	}
}

可见,其write操作的过程是先以整形的方式写入Array的长度,然后依次写入Array的每一个元素。而读操作的过程则正好相反。

注:从以上示例看出,boolean类型在Parcel中也占据四个字节。


4、通用接口

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 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) {
		// 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 Object[]) {
		writeInt(VAL_OBJECTARRAY);
		writeArray((Object[]) v);
	} 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 Serializable) {
		// Must be last
		writeInt(VAL_SERIALIZABLE);
		writeSerializable((Serializable) v);
	} else {
		throw new RuntimeException("Parcel: unable to marshal value " + v);
	}
}

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);
	case VAL_SHORT:
		return (short) readInt();
	case VAL_LONG:
		return readLong();
	case VAL_FLOAT:
		return readFloat();
	case VAL_DOUBLE:
		return readDouble();
	case VAL_BOOLEAN:
		return readInt() == 1;
	case VAL_CHARSEQUENCE:
		return readCharSequence();
	case VAL_LIST:
		return readArrayList(loader);
	case VAL_BOOLEANARRAY:
		return createBooleanArray();        
	case VAL_BYTEARRAY:
		return createByteArray();
	case VAL_STRINGARRAY:
		return readStringArray();
	case VAL_CHARSEQUENCEARRAY:
		return readCharSequenceArray();
	case VAL_IBINDER:
		return readStrongBinder();
	case VAL_OBJECTARRAY:
		return readArray(loader);
	case VAL_INTARRAY:
		return createIntArray();
	case VAL_LONGARRAY:
		return createLongArray();
	case VAL_BYTE:
		return readByte();
	case VAL_SERIALIZABLE:
		return readSerializable();
	case VAL_PARCELABLEARRAY:
		return readParcelableArray(loader);
	case VAL_SPARSEARRAY:
		return readSparseArray(loader);
	case VAL_SPARSEBOOLEANARRAY:
		return readSparseBooleanArray();
	case VAL_BUNDLE:
		return readBundle(loader); // loading will be deferred
	default:
		int off = dataPosition() - 4;
		throw new RuntimeException(
			"Parcel " + this + ": Unmarshalling unknown type code " + type + " at offset " + off);
	}
}

这两个接口依赖于前面基本类型的接口,内部通过instanceof关键字类判断数据类型。各个类型常量定义如下:

private static final int VAL_NULL = -1;
private static final int VAL_STRING = 0;
private static final int VAL_INTEGER = 1;
private static final int VAL_MAP = 2;
private static final int VAL_BUNDLE = 3;
private static final int VAL_PARCELABLE = 4;
private static final int VAL_SHORT = 5;
private static final int VAL_LONG = 6;
private static final int VAL_FLOAT = 7;
private static final int VAL_DOUBLE = 8;
private static final int VAL_BOOLEAN = 9;
private static final int VAL_CHARSEQUENCE = 10;
private static final int VAL_LIST  = 11;
private static final int VAL_SPARSEARRAY = 12;
private static final int VAL_BYTEARRAY = 13;
private static final int VAL_STRINGARRAY = 14;
private static final int VAL_IBINDER = 15;
private static final int VAL_PARCELABLEARRAY = 16;
private static final int VAL_OBJECTARRAY = 17;
private static final int VAL_INTARRAY = 18;
private static final int VAL_LONGARRAY = 19;
private static final int VAL_BYTE = 20;
private static final int VAL_SERIALIZABLE = 21;
private static final int VAL_SPARSEBOOLEANARRAY = 22;
private static final int VAL_BOOLEANARRAY = 23;
private static final int VAL_CHARSEQUENCEARRAY = 24;




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值