Android Parcelable与Parcel.md
Parcelable与Serializable
Serializable是Java为我们提供的一个标准化的序列化接口。
Parcelable是Android为我们提供的序列化的接口。
比较:
- Parcelable相对于Serializable的使用相对复杂一些。
- Parcelable的效率相对Serializable也高很多。Serializable是使用IO流完成的,Parcelable 通过对象指针共享内存,指针挪动。
- Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable在外界有变化的情况下不能很好的保证数据的持续性。尽管Serializable效率低点,但此时还是建议使用Serializable。存储到设备或者网络传输上选择Serializable。
Parcelable是Android为我们提供的序列化的接口,Parcelable相对于Serializable的使用相对复杂一些,但Parcelable的效率相对Serializable也高很多,这一直是Google工程师引以为傲的,有时间的可以看一下Parcelable和Serializable的效率对比 Parcelable vs Serializable 号称快10倍的效率。
选择序列化方法的原则
- 在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
- Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
- Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
序列化与反序列化
序列化:将对象转换为可以传输的二进制流(二进制序列)的过程,这样我们就可以通过序列化,转化为可以在网络传输或者保存到本地的流(序列),从而进行传输数据 。
反序列化:从二进制流(序列)转化为对象的过程。
Parcelable的使用
进行Android开发的时候,无法将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。简单看一下:
实现Parcelable基本有三个步骤:序列化、反序列化、描述。
序列化和反序列化前面已经了解过了,不再赘述。描述指的是返回的是内容的描述信息,只针对一些特殊的需要描述信息的对象,需要返回1,其他情况返回0就可以。
1 | package com.lautung.myapplication; |
writeToParcel:序列化过程
Creator与protected Book(Parcel in)配合实现反序列化,转换为对象。
1 |
|
注意:writeToParcel中writeString的顺序与protected Book(Parcel in) {}
中readString的顺序是一样的。
Parcelable中对象和集合的处理
1 | import android.os.Parcel; |
Book类,需要先实现Parcelable,实现步骤就不贴出来了,和普通的对象一样,实现三个过程。
1 |
|
写入和读取集合有两种方式:
- 一种是写入类的相关信息,然后通过类加载器去读取, –> writeList | readList
- 二是不用类相关信息,创建时传入相关类的CREATOR来创建 –> writeTypeList | readTypeList | createTypedArrayList
第二种效率高一些,但是一定要注意如果有集合定义的时候一定要初始化
public ArrayList<T> demo = new ArrayList<>();
Parcel的简介
Parcel翻译过来是打包的意思,其实就是包装了我们需要传输的数据,然后在Binder中传输,也就是用于跨进程传输数据。
简单来说,Parcel提供了一套机制,可以将序列化之后的数据写入到一个共享内存中,其他进程通过Parcel可以从这块共享内存中读出字节流,并反序列化成对象,下图是这个过程的模型。
Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。
Parcelable通过Parcel实现了read和write的方法,从而实现序列化和反序列化
02-Parcel源码分析
(看源码的工具,使用SourceInsight)
①:初始化流程源码分析
Parcel.java:
1 | mNativePtr == 拿到了 Parcel.cpp 对象指针地址 |
1 | private Parcel(long nativePtr) { |
1 | private void init(long nativePtr) { // mNativePtr == Parcel.cpp 对象指针地址 |
1 | private static native long nativeCreate(); // 注意:从这里进入Native层代码 |
android_os_Parcel.cpp的nativeCreate:
1 | static const JNINativeMethod gParcelMethods[] = { |
再接着搜索,(void*) android_os_Parcel_create 函数即可
1 | static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz) |
②:writeInt源码分析
Parcel.java:
1 | /** |
1 | // 思考:行参一的作用是可以通过此内存地址去寻找native层的C++对象 |
android_os_Parcel.cpp 的 nativeWriteInt:
1 | {"nativeWriteByteArray", "(J[BII)V", (void*)android_os_Parcel_writeByteArray}, |
android_os_Parcel_writeInt 函数:
1 | static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) { |
Parcel.cpp 的 writeInt32:
1 | status_t Parcel::writeInt32(int32_t val) |
1 | template<class T> // 相当于Java的泛型 |
finsihWrite函数:
1 | status_t Parcel::finishWrite(size_t len) |