Android 中parcelable 和 parcel
来源:互联网 发布:网络用词鸡汤什么意思 编辑:程序博客网 时间:2024/05/16 08:51
文章出处:http://blog.csdn.net/shift_wwx
请转载的朋友标明出处~~
前言 :之前一直在用这两个类,但是没有细细的研究,偶尔在网上看到了相关的解释,感觉不是很详细,这里小结一下,如果还有什么遗漏希望有朋友能提出来。
一、parcel
首先说一下parcel,因为parcelable核心也是依赖parcel的。
java中serialize机制,是能将数据对象存入字节流中,在需要的时候重新生成对象,主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。
在Android系统中parcel设计主要是在IPC中通信,将对象存储在内存中,这样效率更高,定位为轻量级的高效的对象序列化和反序列化机制。
(以下路径是在android 4.4中,其他版本的路径可能有点变化,但是应该不大,Parcel毕竟是公共中的公共模块。)
frameworks/base/core/java/android/os/Parcel.java:
public final class Parcel {// final class ...... /** * Retrieve a new Parcel object from the pool. */ 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); } ...... /** * Put a Parcel object back into the pool. You must not touch * the object after this call. */ public final void recycle() { if (DEBUG_RECYCLE) mStack = null; freeBuffer(); final Parcel[] pool; if (mOwnsNativeParcelObject) { pool = sOwnedPool; } else { mNativePtr = 0; pool = sHolderPool; } synchronized (pool) { for (int i=0; i<POOL_SIZE; i++) { if (pool[i] == null) { pool[i] = this; return; } } } } ...... /** * Returns the total amount of data contained in the parcel. */ public final int dataSize() { return nativeDataSize(mNativePtr); } /** * Returns the amount of data remaining to be read from the * parcel. That is, {@link #dataSize}-{@link #dataPosition}. */ public final int dataAvail() { return nativeDataAvail(mNativePtr); } /** * Returns the current position in the parcel data. Never * more than {@link #dataSize}. */ public final int dataPosition() { return nativeDataPosition(mNativePtr); } ...... /** * Write an integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeInt(int val) { nativeWriteInt(mNativePtr, val); } /** * Write a long integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeLong(long val) { nativeWriteLong(mNativePtr, val); } ......}详细的code就不贴出来了,可以查看source code。
1、obtain()
获取一个新的Parcel对象
2、recycle()
清空、回收Parcel对象的内存
3、dataSize()
返回Parcel中所有数据在用的内存
4、dataAvail()
返回Parcel剩下没有读取的data的空间,dataSize - dataPosition
5、dataPosition()
获取Parcel对象数据的偏移
6、dataCapacity()
返回Parcel对象占用的总的内存大小,这个区别于dataSize是所有数据用的内存,还有多余的内存用于re-allocate
7、setDataSize(int)
字节为单位
8、setDataPosition(int)
0 ~ dataSize()
9、setDataCapacity(int)
字节为单位
10、writeInt(int)、writeLong(long)、writeFloat(float)、writeDouble(double)、writeString(string)、writeCharSequence(CharSequence)、writeByte(byte)、writeStrongBinder(IBinder)、writeStrongInterface(IInterface)、writeFileDescriptor(FileDescriptor)
对应的是read**
11、writeValue(Object)、readValue(ClassLoader)
12、Parcel(int nativePtr)
构造函数:
private Parcel(int nativePtr) { if (DEBUG_RECYCLE) { mStack = new RuntimeException(); } //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack); init(nativePtr); } private void init(int nativePtr) { if (nativePtr != 0) { mNativePtr = nativePtr; mOwnsNativeParcelObject = false; } else { mNativePtr = nativeCreate(); mOwnsNativeParcelObject = true; } }不管是wirteInt还是什么都有mNativePtr,就是这里来的,刚新建的Parcel应该是需要nativeCreate的。
上面的接口都是native的接口,来看一下(太多了,找writeInt为例吧):
frameworks/base/core/jni/android_os_Parcel.cpp:
{"nativeWriteInt", "(II)V", (void*)android_os_Parcel_writeInt},
static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jint nativePtr, jint val) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); const status_t err = parcel->writeInt32(val); if (err != NO_ERROR) { signalExceptionForError(env, clazz, err); }}需要调用Parcel类的writeInt32:
frameworks/native/libs/binder/Parcel.cpp:
status_t Parcel::writeInt32(int32_t val){ return writeAligned(val);}
template<class T>status_t Parcel::writeAligned(T val) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(val)) <= mDataCapacity) {restart_write: *reinterpret_cast<T*>(mData+mDataPos) = val; return finishWrite(sizeof(val)); } status_t err = growData(sizeof(val)); if (err == NO_ERROR) goto restart_write; return err;}1、PAD_SIZE
#define PAD_SIZE(s) (((s)+3)&~3)读写时4个字节对齐
2、mDataPos+sizeof(val)) <= mDataCapacity
当小于Parcel的总的大小时候,是可以直接write的。
但是如果不小,那么就需要重新计算大小,然后write
status_t Parcel::growData(size_t len){ size_t newSize = ((mDataSize+len)*3)/2; return (newSize <= mDataSize) ? (status_t) NO_MEMORY : continueWrite(newSize);}mDataSizeSize会多分配50%的大小
continueWrite就是对这些多分配的空间进行初始化、判断,malloc好后进行memcpy,这样的内存操作效率会比Java 序列化中使用外部存储器会高很多。
3、finishWrite(size_t)
status_t Parcel::finishWrite(size_t len){ //printf("Finish write of %d\n", len); mDataPos += len; ALOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos); if (mDataPos > mDataSize) { mDataSize = mDataPos; ALOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize); } //printf("New pos=%d, size=%d\n", mDataPos, mDataSize); return NO_ERROR;}Parcel中data的pos进行偏移,mDataPos记录了当前data最后一次存放的位置。
4、*reinterpret_cast<T*>(mData+mDataPos) = val;
*(mData+mDataPos)指的就是Parcel中data区的指针,将val存进去就可以。
上面就是writeInt的整个过程了。
再来看一下readInt:
template<class T>status_t Parcel::readAligned(T *pArg) const { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(T)) <= mDataSize) { const void* data = mData+mDataPos; mDataPos += sizeof(T); *pArg = *reinterpret_cast<const T*>(data); return NO_ERROR; } else { return NOT_ENOUGH_DATA; }}对比writeInt和readInt你会发现,mDataPos会一直往后,也就是说write的顺序是什么,read的顺序也必须是一样的。
二、Parcelable
之前讲过序列化的意义,在IPC间、网络间等传递对象,我们遇到的不但Intent中会用到,AIDL中也会用到。Parcelable接口相对Java 本身的Serializable稍微复杂了一点,但是效率高,c/c++中完全是对内存直接操作。
1、选择序列化方法的原则:
1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
2、Parcelable接口定义
/** * Interface for classes whose instances can be written to * and restored from a {@link Parcel}. Classes implementing the Parcelable * interface must also have a static field called <code>CREATOR</code>, which * is an object implementing the {@link Parcelable.Creator Parcelable.Creator} * interface.这里说是在用到Parcel进行一些存储的时候,需要用到这个Parcelable 接口。在implements这个Parcelable接口的时候,必须同时顶一个static的变量CREATOR,类型是Parcelable.Creator。
来看一下详细的Parcelable接口:
public interface Parcelable { /** * Flag for use with {@link #writeToParcel}: the object being written * is a return value, that is the result of a function such as * "<code>Parcelable someFunction()</code>", * "<code>void someFunction(out Parcelable)</code>", or * "<code>void someFunction(inout Parcelable)</code>". Some implementations * may want to release resources at this point. */ public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001; /** * Bit masks for use with {@link #describeContents}: each bit represents a * kind of object considered to have potential special significance when * marshalled. */ public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001; /** * Describe the kinds of special objects contained in this Parcelable's * marshalled representation. * * @return a bitmask indicating the set of special object types marshalled * by the Parcelable. */ public int describeContents(); /** * 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, int flags); /** * 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<T> { /** * 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); } /** * Specialization of {@link Creator} that allows you to receive the * ClassLoader the object is being created in. */ public interface ClassLoaderCreator<T> extends Creator<T> { /** * 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()} and * using the given ClassLoader. * * @param source The Parcel to read the object's data from. * @param loader The ClassLoader that this object is being created in. * @return Returns a new instance of the Parcelable class. */ public T createFromParcel(Parcel source, ClassLoader loader); }}1)public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001; //writeToParcel相关操作的时候可能会用到的一个flag,下面会揭示
和public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001; //marshall的时候用到,每个bit代表一个特殊的意义
这两个是不需要重写的
2)public int describeContents();
默认return 0; 就可以,具体做什么有待进一步研究
3)public void writeToParcel(Parcel dest, int flags);
这个是需要实现的,第一个参数是需要write的Parcel,另一个参数是额外的flag,0 或者 之前的flag PARCELABLE_WRITE_RETURN_VALUE
4)public interface Creator<T>
这是必须要的,可以创建一个或者多个Parcelable实例,函数createFromParcel的参数Parcel就是之前writeToParcel中的Parcel。
5)public interface ClassLoaderCreator<T> extends Creator<T> {
继承Creator,函数createFromParcel的第一个参数跟Creator是一样的,第二个参数带了ClassLoader,说明可以反序列化不同ClassLoader中的对象。
三、实例一个
public class MyParcelable implements Parcelable { private int mData; public int describeContents() //直接返回0 { return 0; } public void writeToParcel(Parcel out, int flags) //需要存储的Parcel { out.writeInt(mData); } public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() //必须是public static final 类型 { public MyParcelable createFromParcel(Parcel in) //读出之前writeToParcel中存储的Parcel,可以通过构造函数分别read出来,进行初始化 { return new MyParcelable(in); } public MyParcelable[] newArray(int size) { return new MyParcelable[size]; } }; private MyParcelable(Parcel in)//读出来进行初始化 { mData = in.readInt(); } }请看code中的注释。
- Android中Parcel 和 Parcelable
- Android 中parcelable 和 parcel
- android系列:Parcel 和 Parcelable
- Android初学之Parcel和Parcelable
- 【引】android Parcelable Parcel
- Android之Parcelable, Parcel
- Android - Parcel & Parcelable
- Android - Parcel & Parcelable
- Parcel 和 Parcelable
- Parcel 和 Parcelable
- Parcel 和 Parcelable
- Parcel和Parcelable
- parcel和parcelable
- Parcel 和 Parcelable
- Android Accessibility && Parcel和AIDL && Intent传递对象的两种方法(Serializable,Parcelable)
- Android中 Parcelable和Serializable
- android 中Parcel
- Android中Parcel机制
- 使用Markdown编辑器写博客
- Souvenir
- 凉州馆中与诸判官夜集
- 【转载】MYSQL对时间的处理
- 最长回文子串长度
- Android 中parcelable 和 parcel
- 复制粘贴测试
- iOS 一个字符串显示不同字体、颜色
- Communication Is King;. Clarity and Leadership, Its Humble Servants
- JS ZTREE 的用法
- 括号匹配问题 中缀表达式转换为后缀表达式
- 一个人的旅行
- 自定义错误信息显示位置
- 叹白发