Android中Parcel的解读

时间:2023-01-26 19:39:37

Parcel,翻译过来是“打包”的意思。打包干什么呢?是为了序列化。

    如果要在进程之间传递一个整数,很简单,直接传就是行了;如果要传一个字符串,就稍微复杂了点:需先分配一块可以容纳字符串的内存,然后将字符串复制到内存中,再传递(新手可能问:为啥不直接把字符串的引用传过去呢?学过C/C++的地球人都知道:进程有自己的内存地址空间,一个进程中的1000地址可能在另一个进程中是100000,java对象的引用跟本上还是内存地址);再如果要传递一个类的实例呢?也是先为类分配内存,然后复制一份再传递可以吗?我认为不可以,我至少可以找到一个理由:类中成员除了属性还有方法,即使属性能完整传过去,但还有方法呢?方法是独立于类对象存在的,所以到另一个进程中再引用同一个方法就要出错了,还是因为独立地址空间的原因。

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

  那么到底如何在进程之间传递类对象呢?简单来说可以这样做:在进程A中把类中的非默认值的属性和类的唯一标志打成包(这就叫序列化),把这个包传递到进程B,进程B接收到包后,跟据类的唯一标志把类创建出来,然后把传来的属性更新到类对象中,这样进程A和进程B中就包含了两个完全一样的类对象。

 

详细关于Parcel的使用:

Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。

Parce

1原始类

这类方法们主要读写原始数据类型。它们是:writeByte(byte), readByte(), writeDouble(double), readDouble(), writeFloat(float), readFloat(), writeInt(int), readInt(), writeLong(long), readLong(), writeString(String), readString(). 大多数其它数据的操作都是基于这些方法。

2原始数组类

这类方法用于读写原始数据组成的数组。在向数组写数据时先写入数组的长度再写入数据。读数组的方法可以将数据读到已存在的数组中,也可以创建并返回一个新数组。它们是:

  • writeBooleanArray(boolean[]), readBooleanArray(boolean[]), createBooleanArray()
    writeByteArray(byte[]), writeByteArray(byte[], int, int), readByteArray(byte[]), createByteArray()
    writeCharArray(char[]), readCharArray(char[]), createCharArray()
    writeDoubleArray(double[]), readDoubleArray(double[]), createDoubleArray()
    writeFloatArray(float[]), readFloatArray(float[]), createFloatArray()
    writeIntArray(int[]), readIntArray(int[]), createIntArray()
    writeLongArray(long[]), readLongArray(long[]), createLongArray()
    writeStringArray(String[]), readStringArray(String[]), createStringArray().
    writeSparseBooleanArray(SparseBooleanArray), readSparseBooleanArray().

3 Parcelable类
Parcelable为对象从Parcel中读写自己提供了极其高效的协议。你可以使用直接的方法 writeParcelable(Parcelable, int) 和 readParcelable(ClassLoader) 或 writeParcelableArray(T[], int) and readParcelableArray(ClassLoader) 进行读写。这些方法们把类的信息和数据都写入Parcel,以使将来能使用合适的类装载器重新构造类的实例。

还有一些方法提供了更高效的操作Parcelable们的途径,它们是:writeTypedArray(T[], int), writeTypedList(List), readTypedArray(T[], Parcelable.Creator) and readTypedList(List, Parcelable.Creator)。这些方法不会写入类的信息,取而代之的是:读取时必须能知道数据属于哪个类并传入正确的Parcelable.Creator来创建对象而不是直接构造新对象。(更加高效的读写单个Parcelable对象的方法是:直接调用Parcelable.writeToParcel()和Parcelable.Creator.createFromParcel())

4 Bundles类

Bundles是一种类型安全的Map型容器,可用于存储任何不同类型的数据。它具有很多对讀写数据的性能优化,并且它的类型安全机制避免了当把它的数据封送到Parcel中时由于类型错误引起的BUG的调试的麻烦,可以使用的方法为: writeBundle(Bundle), readBundle(), and readBundle(ClassLoader)。

5 活动对象类

Parcel的一个非同寻常的特性是读写活对象的能力。对于活动对象,它们的内容实际上并没有写入,而是仅写入了一个令牌来引用这个对象。当从Parcel中读取这个对象时,你不会获取一个新的对象实例,而是直接得到那个写入的对象。有两种活动对象可操作:

Binder对象。它是Android跨进程通讯的基础。这种对象可被写入Parcel,并在读取时你将得到原始的对象或一个代理对象(可以想象:在进程内时得到原始的对象,在进程间时得到代理对象)。可以使用的方法们是: writeStrongBinder(IBinder), writeStrongInterface(IInterface), readStrongBinder(), writeBinderArray(IBinder[]), readBinderArray(IBinder[]), createBinderArray(), writeBinderList(List), readBinderList(List), createBinderArrayList()。

FileDescriptor对象。它代表了原始的Linux文件描述符,它可以被写入Parcel并在读取时返回一个ParcelFileDescriptor对象用于操作原始的文件描述符。ParcelFileDescriptor是原始描述符的一个复制:对象和fd不同,但是都操作于同一文件流,使用同一个文件位置指针,等等。可以使用的方法是:writeFileDescriptor(FileDescriptor), readFileDescriptor()。

6无类型容器类

    一类final方法,用于读写标准的java容器类。这些方法们是:writeArray(Object[]), readArray(ClassLoader), writeList(List), readList(List, ClassLoader), readArrayList(ClassLoader), writeMap(Map), readMap(Map, ClassLoader), writeSparseArray(SparseArray), readSparseArray(ClassLoader)。

l的一坨一坨的API用于解决不同类型数据的读写。这些函数们主要有六种类型。

PS:转载 个人学习。。。