parcel.doc

上传人:sk****8 文档编号:3534491 上传时间:2019-06-02 格式:DOC 页数:34 大小:239KB
下载 相关 举报
parcel.doc_第1页
第1页 / 共34页
parcel.doc_第2页
第2页 / 共34页
parcel.doc_第3页
第3页 / 共34页
parcel.doc_第4页
第4页 / 共34页
parcel.doc_第5页
第5页 / 共34页
点击查看更多>>
资源描述

1、一先从 Serialize 说起我们都知道 JAVA 中的 Serialize 机制,译成串行化、序列化,其作用是能将数据对象存入字节流当中,在需要时重新生成对象。主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。二Android 中的新的序列化机制在 Android 系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中采用了新的 IPC(进程间通信)机制,必然要求使用性能更出色的对象传输方式。在这样的环境下,Parcel 被设计出来,其定位就是轻量级的高效的对象序列化和反序列化机制。三Parcel 类的背后在 Framework 中有 parcel 类,源码路径是:

2、Frameworks/base/core/java/android/os/Parcel.java典型的源码片断如下:java 代码: 1. /*2. * Write an integer value into the parcel at the current dataPosition(),3. * growing dataCapacity() if needed.4. */5. public final native void writeInt(int val); 6.7. /*8. * Write a long integer value into the parcel at the cu

3、rrent dataPosition(),9. * growing dataCapacity() if needed.10.*/11.public final native void writeLong(long val); 复制代码从中我们看到,从这个源程序文件中我们看不到真正的功能是如何实现的,必须透过 JNI 往下走了。于是,Frameworks/base/core/jni/android_util_Binder.cpp 中找到了线索java 代码:1. static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz,

4、jint val)2. 3. Parcel* parcel = parcelForJavaObject(env, clazz);4. if (parcel != NULL) 5. const status_t err = parcel-writeInt32(val);6. if (err != NO_ERROR) 7. jniThrowException(env, “java/lang/OutOfMemoryError”, NULL);8. 9. 10. 11.12.static void android_os_Parcel_writeLong(JNIEnv* env, jobject cla

5、zz, jlong val)13.14.Parcel* parcel = parcelForJavaObject(env, clazz);15.if (parcel != NULL) 16.const status_t err = parcel-writeInt64(val);17.if (err != NO_ERROR) 18.jniThrowException(env, “java/lang/OutOfMemoryError”, NULL);19.20.21. 复制代码从这里我们可以得到的信息是函数的实现依赖于 Parcel 指针,因此还需要找到Parcel 的类定义,注意,这里的类已经是

6、用 C+语言实现的了。找到 Frameworks/base/include/binder/parcel.h 和Frameworks/base/libs/binder/parcel.cpp。终于找到了最终的实现代码了。有兴趣的朋友可以自己读一下,不难理解,这里把基本的思路总结一下:1. 整个读写全是在内存中进行,主要是通过 malloc()、realloc()、memcpy()等内存操作进行,所以效率比 JAVA 序列化中使用外部存储器会高很多;2. 读写时是 4 字节对齐的,可以看到#define PAD_SIZE(s) (s)+3)会一次多分配50%;4. 对于普通数据,使用的是 mData

7、 内存地址,对于 IBinder 类型的数据以及FileDescriptor 使用的是 mObjects 内存地址。后者是通过 flatten_binder()和unflatten_binder()实现的,目的是反序列化时读出的对象就是原对象而不用重新 new 一个新对象。Android Parcel 理解 2010-09-25 20:43:47| 分类: 转载文章 | 标签: |字号大中小 订阅 android 中 Parcel 的使用,他是一个存储基本数据类型和引用数据类型的容器,在 andorid 中通过IBinder 来绑定数据在进程间传递数据。Parcel parcel = Parc

8、el.obtain();/ 获取一个 Parcel 对象下面就可以对其进行方法进行操作了,createXXX(),wirteXXX(),readXXX(),其中 dataPosition(),返回当前 Parcel 当前对象存储数据的偏移量,而 setDataPosition(),设置当前 Parcel 对象的偏移量,方便读取 parcel 中的数据,可问题就出在我读取出来的数据要么是空(null),要么永远是第一个偏移量处的值,存储和读取数据的。Parcel 采用什么机制实现的,是以什么形式的存储的,然后我才能任意对其操作,读取目标数据。基本数据类型的取值范围,boolean 1bitsho

9、rt 16bitint 32bitlong 64bitfloat 32bitdouble 64bitchar 16bitbyte 8bit由此我可以猜想,Parcel 32bit 作为基本单位存储写入的变量,4byte*8=32bit,在内存中的引用地址变量是采用 16 进制进行编码,且作为偏移量,即偏移量是 4 的倍数,0,4,8,12,16,20,24,28,32,36,40,44,48.4*N,f(x) = 4*yy=0parcel.writeInt(2);parcel.writeInt(3);parcel.writeInt(4);parcel.writeInt(5);parcel.wr

10、iteInt(6);parcel.writeInt(7);parcel.writeInt(81011111);parcel.writeFloat(1f);parcel.writeFloat(1000000000000000000000000000000000000f);parcel.writeXXX(),每写一次数据,在 32bit 的空间里能够存储要放入的变量,怎只占一个偏移量,也就之一动 4 个位置,而当存储的数据如 parcel.writeFloat(1000000000000000000000000000000000000f);他就自动往后移动, parcel.writeString(

11、“a“);parcel.writeString(“b“);parcel.writeString(“d“);parcel.writeString(“c“);和parcel.writeString(“abcd“); 的区别。有此可见,他的内存的分配原来是这样的。那我怎样才能把我存进去的书据依次的去出来呢?setDataPosition(), 设置 parcel 的偏移量,在readXXX(),读取数据int size = parcel.dataSize();int i = 0;while (i =dataSize()值 (以空间换时间)dataPostion() 获得当前 parcel 对象的偏移

12、量(类似于文件流指针的偏移量)setDataPosition() 设置偏移量recyle() 清空、回收 parcel 对象的内存writeInt(int) 写入一个整数writeFloat(float) 写入一个浮点数writeDouble(double) 写入一个双精度数writeString(string) 写入一个字符串当然,还有更多的 writeXXX()方法,与之对应的就是 readXXX(),具体方法请参阅 SDK。其中几个值得注意的方法为:writeException() 在 Parcel 队头写入一个异常writeException() Parcel 队头写入“ 无异常“re

13、adException() 在 Parcel 队头读取,若读取值为异常,则抛出该异常;否则,程序正常运行。一、Parcel 的分析相信看了前面的值,对 Parcel 的使用该有了初步印象。那么,Parcel 的内部存储机制是怎么样的?偏移量又是什么情况?让我们回忆一下基本数据类型的取值范围:boolean 1bit 1 字节char 16bit 2 字节int 32bit 4 字节long 64bit 8 字节float 32bit 4 字节double 64bit 8 字节如果大家对 C 语言熟悉的话,C 语言中结构体的内存对齐和 Parcel 采用的内存存放机制一样,即读取最小字节为 32

14、bit,也即 4 个字节。高于 4 个字节的,以实际数据类型进行存放,但得为4byte 的倍数。基本公式如下:实际存放字节:判别一: 32bit (32bit) 例如:long ,float ,String ,数组等当我们使用 readXXX()方法时,读取方法也如上述:实际读取字节:判别一: 32bit (32bit) 例如:long ,float ,String ,数值等由上可以知道,当我们写入/读取一个数据时,偏移量至少为 4byte(32bit),于是,偏移量的公式如下:f(x)= 4x (x=0,1,n)事实上,我们可以显示的通过 setDataPostion(int postion

15、) 来直接操作我们欲读取数据时的偏移量。毫无疑问,你可以设置任何偏移量,但所读取的值是类型可能有误。因此显示设置偏移量读取值的时候,需要小心。另外一个注意点就是我们在 writeXXX()和 readXXX()时,导致的偏移量是共用的,例如,我们在 writeInt(23)后,此时的 datapostion=4,如果我们想读取 5,简单的通过 readInt()是不行的,只能得到 0。这时我们只能通过setDataPosition(0)设置为起始偏移量,从起始位置读取四个字节,即 23。因此,在读取某个值时,可能需要使用setDataPostion(int postion)使偏移量装换到我们的

16、值处。巧用 setDataPosition()方法,当我们的 parcel 对象中只存在某一类型时,我们就可以通过这个方法来快速的读取所有值。具体方法如下:html view plaincopyprint?1. /* 2. * 前提条件,Parcel 存在多个类型相同的对象,本例子以 10 个 float 对象说明:3. */ 4. public void readSameType() 5. Parcel parcel =Parcel.obtain() ; 6. for (int i = 0; i “ + getParcelInfo(); 9. 10. /方法一 ,显示设置偏移量 11. in

17、t i = 0; 12. int datasize = parcel.dataSize(); 13. while (i “ + getParcelInfo(); 17. i += 8; / double 占用字节为 8byte 18. 19. / 方法二,由于对象的类型一致,我们可以直接利用 readXXX()读取值会产生偏移量 20. / parcel.setDataPosition(0) ; / 21. / while(parcel.dataPosition()“ + getParcelInfo(); 24. / 25. 由于可能存在读取值的偏差,一个默认的取值规范为:1、 读取复杂对象时: 对象匹配时,返回当前偏移位置的该对象;对象不匹配时,返回 null 对象 ;2、 读取简单对象时: 对象匹配时,返回当前偏移位置的该对象 ;对象不匹配时,返回 0;下面,给出一张浅显的 Parcel 的存放空间图,希望大家在理解的同时,更能体味其中滋味。有点简单,求谅解。相信通过前面的介绍,你一定很了解了了 Parcel 的存储机制,下面给定一应用程序来实践。1、布局文件如下: html view plaincopyprint?1. 2. 5. 7. 9. 11. 13. 14. 16. 18. 20. 21. 23. 26. 28. 30. 31.

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 实用文档资料库 > 策划方案

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。