`
dowhathowtodo
  • 浏览: 771159 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多
序列化数据原理:
序列化的过程就是对象写入字节流和从字节流中读取对象。将对象状态转换成字节流之后,可以用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);        
    }

	@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]; // 传递数组
			}
		};
	}
}

打印结果:
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函数


分享到:
评论

相关推荐

    Android中Serializable和Parcelable序列化对象详解

    本文详细对Android中Serializable和Parcelable序列化对象进行学习,具体内容如下 学习内容: 1.序列化的目的 2.Android中序列化的两种方式 3.Parcelable与Serializable的性能比较 4.Android中如何使用Parcelable进行...

    Android序列化传递数据

    本代码就是简单的Parcelable与Serializable序列化,包括bitmap数组如何在应用中传递...

    android序列化实现

    Parcelable和Serializable两种序列化实现,大家自行搜索关于两种序列化的优劣以及具体的序列化方式。 、

    Android Intent传递数据大小限制详解

    Intent可以携带一些数据,比如基本类型数据int、Boolean,或是String,或是序列化对象,Parcelable与Serializable。 Intent传递数据时,如果数据太大,可能会出现异常。比如App闪退,或是Intent发送不成功,logcat...

    Android中Parcelable的使用详解

    Parcelable是Android为我们提供的序列化的接口。 对比: 1、Parcelable相对于Serializable的使用相对复杂一些。 2、Parcelable的效率相对Serializable也高很多。 3、Parcelable不能使用在要将数据存储在磁盘上的情况...

    android Parcelable

    经常要在Activity之间传递参数,使用Android系统提供的方法可以传递基本数据类型的变量,但有时候我们经常要传递一些复杂的数据类型或自定义的类,这种情况的参数无法直接传递,我们可以通过序列化实现 public ...

    Android序列化之Parcelable和Serializable的使用详解

    反序列化恰恰是序列化的反向操作,也就是说,把已存在在磁盘或者其他介质中的对象,反序列化(读取)到内存中,以便后续操作,而这个过程就叫做反序列化。 概括性来说序列化是指将对象实例的状态存储到存储媒体...

    Android AIDL使用介绍(2)自定义数据类型的传递

    1.背景 默认情况下,AIDL只支持下列数据类型: Java八种基础数据类型(如 int、long、char、boolean 等);...这就需用到Parcelable接口,Parcelable意思是“可包裹的”,是Android系统可用的序列化

    Android中Intent传递对象的两种方法Serializable,Parcelable

    Android中的传递有两个方法,一个是Serializable,另一个...3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还

    Intent传递对象之Serializable和Parcelable的区别

    Intent在不同的组件中传递对象数据的应用非常普遍,大家都知道在intent传递对象的方法有两种:1、实现Serializable接口、2、实现Parcelable接口。 Android中Intent传递对象的两种方法Serializable,Parcelable请点击...

    Activity传递类对象源码

    Activity间要传递数据,很多时候简单的int和string满足不了需求,我们在面向对象中已经习惯了类和对象, 那么下面就说一下如何传递类...一个是Java的序列化(Serializable),另一个是Android的Parcelable序列化方法。

    AutoPage:Android活动轻松跳

    不再支持可序列化的数据传输,而是使用性能更好的Parcelable大对象传输 支持多进程活动跳转 减少内存占用并改善可回收内存 AutoPage v1.0.4 如果您认为这很好,请给我一颗星 Android活动轻松跳转 每当活动或片段...

    Android开发中Intent传递对象的方法分析

    利用方法:public Intent putExtra (String name, Parcelable value)传递一个Parceable的参数,此方法的参数被序列化到内存。 利用方法:public Intent putExtra (String name, Serializable value)传递一个实现了...

    Android之使用Bundle进行IPC详解

    当然,传输的数据必须能够被序列化,比如基本类型、实现了Parcelable接口的对象、实现了Serializable接口的对象以及一些Android支持的特殊对象,具体内容可以看Bundle这个类,就可以看到所有它支持的类型。...

    Android使用文件进行IPC

    在Windows上,一个文件如果被加了排斥锁将会导致其他线程无法对其进行访问,包括读写,而由于Android系统基于Linux,使其并发读/写文件可以没有限制地进行,甚至两个线程同时对同一个文件进行读写操作是允许的,尽管...

Global site tag (gtag.js) - Google Analytics