序列化数据原理:
序列化的过程就是对象写入字节流和从字节流中读取对象。将对象状态转换成字节流之后,可以用java.io包中的各种字节流类将其保存到文件中,管道到另一线程中或通过网络连接将对象数据发送到另一主机。
简单说就是将数据对象存入字节流当中,在需要时重新生成对象。

Android中的序列化机制:
首先android系统利用Binder进行IPC通讯,且定位为针对内存受限的设备,所以则要求使用高效的对象传输方式,因为Parcel应运而生。

代码分析:
frameworks\base\core\java\android\os\Parcel.java
frameworks\base\core\jni\android_util_Binder.cpp JNI函数

以典型代码片段举例:
    /**     * Write an integer value into the parcel at the current dataPosition(),     * growing dataCapacity() if needed.     */    public final native void writeInt(int val);    /**     * Write a long integer value into the parcel at the current dataPosition(),     * growing dataCapacity() if needed.     */    public final native void writeLong(long val);    /**     * Write a floating point value into the parcel at the current     * dataPosition(), growing dataCapacity() if needed.     */    public final native void writeFloat(float val);

JNI层实现:
static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz, jint val){    Parcel* parcel = parcelForJavaObject(env, clazz);    if (parcel != NULL) {        const status_t err = parcel->writeInt32(val);        if (err != NO_ERROR) {            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);        }    }}static void android_os_Parcel_writeLong(JNIEnv* env, jobject clazz, jlong val){    Parcel* parcel = parcelForJavaObject(env, clazz);    if (parcel != NULL) {        const status_t err = parcel->writeInt64(val);        if (err != NO_ERROR) {            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);        }    }}static void android_os_Parcel_writeFloat(JNIEnv* env, jobject clazz, jfloat val){    Parcel* parcel = parcelForJavaObject(env, clazz);    if (parcel != NULL) {        const status_t err = parcel->writeFloat(val);        if (err != NO_ERROR) {            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);        }    }}

其本质使用 Parcel 对象来完成的,实现代码在:frameworks/base/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;}status_t Parcel::growData(size_t len){    size_t newSize = ((mDataSize+len)*3)/2;  // 每次多分配50%的内存空间    return (newSize <= mDataSize)            ? (status_t) NO_MEMORY            : continueWrite(newSize);}


总结:
1、整个读写全是在内存中进行,主要是通过malloc()、realloc()、memcpy()等内存操作进行
2、读写时是PAD_SIZE=4字节对齐, #define PAD_SIZE(s) (((s)+3)&~3)
3、预分配的空间不够时newSize = ((mDataSize+len)*3)/2;会一次多分配50%
4、普通数据,使用的是mData内存地址,对于IBinder类型的数据以及FileDescriptor使用的是mObjects内存地址


举个例子说明一下如何在同一个Activity传递复杂数据类型:

package com.test.testparcel;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.os.Parcel;import android.os.Parcelable;import android.util.Log;import android.view.KeyEvent;public class TestParcelActivity extends Activity {ComplexDataStruct complexData = null;    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);            }@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event) {if(keyCode == KeyEvent.KEYCODE_0){        testComplexDS();}return super.onKeyUp(keyCode, event);}    public void testComplexDS(){complexData = new ComplexDataStruct();Intent intent=new Intent(TestParcelActivity.this,TestParcelActivity.class);complexData.a = 10;complexData.b = 20;complexData.str1 = " hello...";complexData.str2 = " world...";Log.i("","intent.putExtra before");intent.putExtra("testcomplexData", complexData);Log.i("","intent.putExtra after");Log.i("","intent.getParcelableExtra before");ComplexDataStruct test = (ComplexDataStruct)intent.getParcelableExtra("testcomplexData");Log.i("","intent.getParcelableExtra after");Log.i("","a="+test.a);Log.i("","b="+test.b);Log.i("","str1="+test.str1);Log.i("","str2="+test.str2);}/* 一个复杂的Parcelable对象传递 */public class ComplexDataStruct implements Parcelable{public int a = 0;public int b = 0;public String str1 = null;public String str2 = null;ComplexDataStruct(){//TODO}public ComplexDataStruct(ComplexDataStruct other) {this.a = other.a;this.b = other.b;this.str1 = other.str1;this.str2 = other.str2;}private ComplexDataStruct(Parcel in) {Log.e("","readFromParcel is calling...");readFromParcel(in);}public void readFromParcel(Parcel in) {a = in.readInt();b = in.readInt();str1 = in.readString();str2 = in.readString();Log.e("","readFromParcel is calling...");}public int describeContents() {// TODO Auto-generated method stubreturn 0;}public void writeToParcel(Parcel arg0, int arg1) {// TODO Auto-generated method stubLog.e("","writeToParcel is calling...");arg0.writeInt(a);arg0.writeInt(b);arg0.writeString(str1);arg0.writeString(str2);Log.e("","writeToParcel is calling...");}/* 内部实现静态CREATOR类 */public final Parcelable.Creator<ComplexDataStruct> CREATOR = new Parcelable.Creator<ComplexDataStruct>() {// 从Parcel中读取数据,返回ComplexDataStruct对象public ComplexDataStruct createFromParcel(Parcel in) {Log.e("","createFromParcel is calling...");return new ComplexDataStruct(in);}public ComplexDataStruct[] newArray(int size) {Log.e("","newArray is calling...");return new ComplexDataStruct[size]; // 传递数组}};}}

打印结果:
I/ ( 1324): intent.putExtra before
I/ ( 1324): intent.putExtra after
I/ ( 1324): intent.getParcelableExtra before
I/ ( 1324): intent.getParcelableExtra after
I/ ( 1324): a=10
I/ ( 1324): b=20
I/ ( 1324): str1= hello...
I/ ( 1324): str2= world...


这里利用 intent 发送消息,利用 Bundle 来传递数据,Bundle概念下一篇会讲到。

构建复杂数据类型,需要如下实现:
1、继承自 Parcelable 实现,ex: public class ComplexDataStruct implements Parcelable
2、内部有一个静态的 CREATOR 类 : public static final Parcelable.Creator<ComplexDataStruct> CREATOR
3、实现 writeToParcel 和 readFromParcel 序列化与反序列化函数

4、传递使用 Intent.java 类的函数:putExtra 及 getParcelableXXX函数


更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. Android设备MTP方式连接PC增删文件无法实时更新的问题
  4. android项目创建xml和存储xml文件
  5. Android(安卓)完整地操作数据库--日记本实例
  6. 【Android(安卓)Training - 06】分享数据内容 [Lesson 2 - 从其
  7. Android(安卓)数据持久化(SQLite数据存储)
  8. android 缓存管理与常用算法
  9. Android(安卓)图片下载本地内存的缓存方式

随机推荐

  1. Oracle OCP 19c 认证1Z0-082考试题库(第6
  2. 字节三面:详解一条 SQL 的执行过程
  3. 如何检测社交网络中两个人是否是朋友关系
  4. ubuntu系统如何配置***检测系统AIDE?
  5. CISSP学习:第6章密码学和对称密钥算法
  6. 一个简易的通讯录的实现
  7. 航电oj2013-2015 参考代码
  8. 巧妙避坑篇——测试代码时你会犯的 10个
  9. 物理网卡故障,怎么办?
  10. 2020.2.22 每日小结