码迷,mamicode.com
首页 > 其他好文 > 详细

序列化手段——parcel例子详解

时间:2015-02-13 11:44:50      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:parcel   序列化   android   

Parcel其翻译为“包袱”、“包裹”。在Android系统中Binder进程间通信(IPC)中经常使用到Parcel类对象来实现客户端和服务端的数据交互,而AIDL技术也是通过Parcel来实现交互。

查阅Android源码Parcel类,其中常用方法有
obtain() 获得一个新的parcel对象,相当于java中new一个对象
dataSize() 得到当前parcel对象的实际存储空间 
dataCapacity() 得到当前parcel对象的已分配的存储空间,该值大于或等于dataSize()返回值 。
dataPostion() 获得当前parcel对象的偏移量(类似于文件流指针的偏移量) 
setDataPosition() 设置偏移量(类似于移动指针到特定位置)
recyle() 清空并回收parcel对象所占内存
writeXXX()方法表示写于一个XXX类型的数
readXXX()方法表示读取一个XXX类型的数
比如:writeInt(int) 写入一个整数;readInt()读取一个整数。
值得注意的是,读取或写入特定类型的数之后会导致偏移量的变化,对于同一个parcel对象,偏移量是公用的。其以一个字节作为一个单位,假设去读一个32bit的float(java语言),则偏移量为4。
引用网友的一张图片

技术分享

下面通过一个Android的小例子来认识这个类的使用
MainActivity类代码

package com.example.androidtest_parcel;

import android.os.Bundle;
import android.os.Parcel;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{
	
	private Button mWI,mWF,MWD;
	private Button mRI,mRF,mRD;
	private TextView mTextView1;
	private EditText mEdit;
	private Parcel mParcel;
	private int position;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
		initListener();
		//获取Parcel对象
		mParcel = Parcel.obtain();
	}

	public void initView(){
		mWI= (Button)findViewById(R.id.writeInt);
		mWF= (Button)findViewById(R.id.writeFloat);
		MWD= (Button)findViewById(R.id.writeDouble);
		mRI= (Button)findViewById(R.id.readInt);
		mRF= (Button)findViewById(R.id.readFloat);
		mRD= (Button)findViewById(R.id.readDouble);
		mEdit = (EditText)findViewById(R.id.writePosition);
		mTextView1 = (TextView)findViewById(R.id.textView1);
	}
	
	public void initListener(){
		mWI.setOnClickListener(this);
		mWF.setOnClickListener(this);
		MWD.setOnClickListener(this);
		mRI.setOnClickListener(this);
		mRF.setOnClickListener(this);
		mRD.setOnClickListener(this);
		mTextView1 = (TextView)findViewById(R.id.textView1);
	}
	
	public void showMyParcelDouble(){
		
		int allSize = mParcel.dataCapacity();//当前分配的空间
		int realSize = mParcel.dataSize();//当前实际存储空间
		mParcel.setDataPosition(Integer.parseInt(mEdit.getText().toString()));
		int realPosition  = mParcel.dataPosition();//当前偏移量
		mTextView1.setText("当前分配空间:"+allSize+'\n'+
				"当前实际存储空间:"+realSize+'\n'+
				"当前偏移量:"+realPosition+'\n'+
				'\n'+
				"当前读取到的数为:"+mParcel.readDouble());
	}
	public void showMyParcelFloat(){
		
		int allSize = mParcel.dataCapacity();//当前分配的空间
		int realSize = mParcel.dataSize();//当前实际存储空间
		mParcel.setDataPosition(Integer.parseInt(mEdit.getText().toString()));
		int realPosition  = mParcel.dataPosition();//当前偏移量
		mTextView1.setText("当前分配空间:"+allSize+'\n'+
				"当前实际存储空间:"+realSize+'\n'+
				"当前偏移量:"+realPosition+'\n'+
				'\n'+
				"当前读取到的数为:"+mParcel.readFloat());
	}
	public void showMyParcelInt(){
		
		int allSize = mParcel.dataCapacity();//当前分配的空间t
		int realSize = mParcel.dataSize();//当前实际存储空间
		mParcel.setDataPosition(Integer.parseInt(mEdit.getText().toString()));
		int realPosition  = mParcel.dataPosition();//当前偏移量
		mTextView1.setText("当前分配空间:"+allSize+'\n'+
				"当前实际存储空间:"+realSize+'\n'+
				"当前偏移量:"+realPosition+'\n'+
				'\n'+
				"当前读取到的数为:"+mParcel.readInt());
	}
	
	public void showMyParcel(){
		
		int allSize = mParcel.dataCapacity();//当前分配的空间
		int realSize = mParcel.dataSize();//当前实际存储空间
		int realPosition  = mParcel.dataPosition();//当前偏移量
		mTextView1.setText("当前分配空间:"+allSize+'\n'+
				"当前实际存储空间:"+realSize+'\n'+
				"当前偏移量:"+realPosition+'\n'+
				'\n'+
				"当前没有读取");
	}
	
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.writeInt:
			mParcel.writeInt(10);
			showMyParcel();
			break;
		case R.id.writeFloat:
			mParcel.writeFloat(20);
			showMyParcel();
			break;
		case R.id.writeDouble:
			mParcel.writeDouble(30);
			showMyParcel();
			break;
		case R.id.readInt:
			showMyParcelInt();			
			break;
		case R.id.readFloat:			
			showMyParcelFloat();
			break;
		case R.id.readDouble:			
			showMyParcelDouble();
			break;

		default:
			break;
		}
		
	}

}

xml布局代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

    <Button
        android:id="@+id/writeInt"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="写入一个int" />
    
     <Button
        android:id="@+id/readInt"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="读取一个int" />
    
    </LinearLayout>
    
        <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

    <Button
        android:id="@+id/writeFloat"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="写入一个float" />
    
     <Button
        android:id="@+id/readFloat"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="读取一个float" />
    
    </LinearLayout>


    
        <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

    <Button
        android:id="@+id/writeDouble"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="写入一个double" />
    
     <Button
        android:id="@+id/readDouble"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="读取一个double" />
    
    </LinearLayout>
    
               <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

    <TextView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="写入偏移量:" 
        android:textSize="20dp"/>
    
     <EditText
        android:id="@+id/writePosition"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:hint="此处输入偏移量" />
    
    </LinearLayout>


    <TextView
        android:layout_marginTop="10dp"
        android:id="@+id/textView1"
        android:layout_width="fill_parent"
        android:layout_height="200dp"/>

</LinearLayout>

先看下效果图

技术分享

主要的思路是:可以通过做左边三种基本类型写入mParcel,然后可以根据自己输入的特定偏移量来使用右边三个读取键。之所以需要自己设置偏移量就是使用Parcel类对象来存储时,读取时需要按照存储的时候的存储顺序,这也导致在IPC通信中,服务端Binder和驱动端Binder对Parcel对象的操作需要约定要顺序规则,AIDL因此而生。

再看效果图:我一次点击“写入一个int”,“写入一个float”,“写入一个double”。为了测试需要数据我都固定了,在底部空白处有一个TextView显示当前mParcel的信息。

技术分享   技术分享   技术分享

此时对应的parcel当前分配的空间、实际存储空间和偏移量都有了变化。细心的朋友可能会发现,当前分配的空间总是实际存储空间的百分之150。
我在按照特定的偏移量取出数据(注意:如果没有按照特定偏移量,将读取不到正确的数据)
再看效果图:我输入分别输入偏移量3/0/5点击“读取一个int”

技术分享  技术分享  技术分享

我们可以看到只有从偏移量0处在能正确读取到我们输入的int:原因就是我们上面方法所述,系统会以4个字节为一个读取单位来读取int。而至于从3-6字节的读取、5-8字节的读取,所读到的数可以按照二进制位数来进行推导,这里就不做强调。
我再分别输入“4”点击“读取一个float”,输入“8”点击“读取一个double”

技术分享  技术分享

到此基本的例子都演示完毕来了。
在这里有一个疑问,既然能序列化基本类型,那么序列化对象也可以吧?而且一般我们在实际开发的过程中序列化对象是比较常用的。事实上,Android提供了一个序列化接口Parcelable,实现这个接口将可以对实现类进行序列化。而Parcel主要是用来序列化基本类型的。因此一般来说,如果操作基本类型则用Parcel就可以,而需要操作到引用对象,则用序列化接口Parcelable。




序列化手段——parcel例子详解

标签:parcel   序列化   android   

原文地址:http://blog.csdn.net/u010794180/article/details/43791691

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!