您的位置:首页 > 移动开发 > Android开发

Android -- Parcelable 序列化操作数据(上篇)

2016-04-09 15:27 344 查看
http://blog.csdn.net/andyhuabing/article/details/7703401

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

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

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

以典型代码片段举例:

[java] view
plain copy

 print?

<span style="font-size:16px;">    /** 

     * 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);</span>  

JNI层实现:

[cpp] view
plain copy

 print?

<span style="font-size:16px;">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);  

        }  

    }  

}</span>  

其本质使用 Parcel 对象来完成的,实现代码在:frameworks/base/libs/binder/parcel.cpp

[cpp] view
plain copy

 print?

<span style="font-size:16px;">  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);  

    }   </span>  

总结:
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传递复杂数据类型:

[java] view
plain copy

 print?

<span style="font-size:16px;">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);          

    }  

  

    @Override  

    public 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 stub  

            return 0;  

        }  

  

        public void writeToParcel(Parcel arg0, int arg1) {  

            // TODO Auto-generated method stub  

            Log.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]; // 传递数组  

            }  

        };  

    }  

}</span>  

打印结果:

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函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: