序列化手段(1)——parcel例子详解

来源:互联网 发布:网络预约挂号流程 编辑:程序博客网 时间:2024/06/06 12:43
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;@Overrideprotected 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();//当前分配的空间tint 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'+"当前没有读取");}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (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。
想进一步了解Android序列化Parcelable及其Serializable的应用场景详细解析:点击打开链接
Parcelable及其Serializable的编程实现演示:点击打开链接





0 0
原创粉丝点击