子墨苑

每天学习一点点。

导航

Android中的Parcel和Parcelable

对于Android来说传递复杂类型,主要是将自己的类转换为基础的字节数组,Activity之间传递数据是通过Intent实现的。 Android序列化对象主要有两种方法,实现Serializable接口、或者实现Parcelable接口。实现Serializable接口是JavaSE本身就支持的,而Parcelable是Android特有的功能,效率比实现Serializable接口高,而且还可以用在进程间通信(IPC)中。实现Serializable接口非常简单,声明一下就可以了。而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。

 

Parcel 在英文中有两个意思,其一是名词,为包裹,小包的意思; 其二为动词,意为打包,扎包。邮寄快递中的包裹也用的是这个词。Android采用这个词来表示封装消息数据。这个是通过IBinder通信的消息的载体。需要明确的是Parcel用来存放数据的是内存(RAM),而不是永久性介质(Nand等)。

 

Parcelable,定义了将数据写入Parcel,和从Parcel中读出的接口。一个实体(用类来表示),如果需要封装到消息中去,就必须实现这一接口,实现了这一接口,该实体就成为“可打包的”了。

 

Parcelable接口的作用:实现了Parcelable接口的实例可以将自身的状态信息(状态信息通常指的是各成员变量的值)写入Parcel,也可以从Parcel中恢复其状态。Parcel用来完成数据的序列化传递。下面就介绍一下实现Parcelable接口的方法。

通过实现Parcelable接口序列化对象的步骤:

1. 实现Parcelable接口。

2. 实现Parcelable接口的public void writeToParcel(Parcel dest, int flags)方法 。

3. 自定义类型中必须含有一个名称为CREATOR的静态成员,该成员对象要求实现Parcelable.Creator接口及其方法。

简而言之:通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的顺序和读的顺序必须一致。 clip_image002

在实现Parcelable的实现中,规定了必须定义一个静态成员, 初始化为嵌入接口的实现类。

 

Intent 可以携带对象来在不同的Activity中传递数据,要传递的数据必须实现三个方法

1. describeContents()返回0就可以

2. writeToParcel(Parcel parcel, int flag) 把需要写入的数据写入Parcel中,然后框架调用此方法发送给接收端的Activity

3. public static final Parcelable.Creator<ParcelableObject> CREATOR 外部类反序列化该类时调用此方法

一定要注意:写入parcel和反序列化parcel时顺序一定要相同,不然数据会出错

 

案例介绍:

/**  
 * ParcelableObject.java  
 * com.androidtest.parcelable  
 *  
 * Function: TODO  
 *  
 *   ver     date           author  
 * ──────────────────────────────────  
 *           2011-5-11      Leon  
 *  
 * Copyright (c) 2011, TNT All Rights Reserved.  
*/  
   
package com.androidtest.parcelable;  
   
import android.os.Parcel;  
import android.os.Parcelable;  
   
/**  
 * ClassName:ParcelableObject 需要实现三个方法,describeContents()返回0就可以 、 writeToParcel(Parcel parcel, int flag)  
 * 写入Parcel和public static final Parcelable.Creator  
<parcelableobject><span style="font-size: 14px"> CREATOR 供外部类反序列化该类  
 * 一定要注意顺序后面这个两个函数读和写的顺序要相同,不然数据会出错  
 * Function: TODO  
 * Reason:   TODO ADD REASON  
 *  
 * @author   Leon  
 * @version  
 * @since    Ver 1.1  
 * @Date     2011-5-11  
 */  
public class ParcelableObject implements Parcelable{  
    private  String  name  ;  
    private  String  surName ;  
    private  int     age ;   
   
    public String getName() {  
        return name;  
    }  
   
    public void setName(String name) {  
        this.name = name;  
    }  
   
    public String getSurName() {  
        return surName;  
    }  
   
    public void setSurName(String surName) {  
        this.surName = surName;  
    }  
   
    public int getAge() {  
        return age;  
    }  
   
    public void setAge(int age) {  
        this.age = age;  
    }  
   
    @Override  
    public int describeContents() {  
   
        // TODO Auto-generated method stub  
        return 0;  
   
    }  
   
    @Override  
    public void writeToParcel(Parcel dest, int flag) {  
   
        // TODO Auto-generated method stub  
   
        dest.writeInt(age);  
        dest.writeString(name);  
        dest.writeString(surName);  
   
    }  
    public static final Parcelable.Creator CREATOR = new Creator() {  
   
        @Override  
        public ParcelableObject createFromParcel(Parcel source) {  
   
            // TODO Auto-generated method stub  
            ParcelableObject parcelableObj = new ParcelableObject();  
            parcelableObj.age=source.readInt();  
            parcelableObj.surName=source.readString();  
            parcelableObj.name = source.readString();  
            return parcelableObj;  
   
        }  
   
        @Override  
        public ParcelableObject[] newArray(int size) {  
   
            // TODO Auto-generated method stub  
            return new ParcelableObject[size];  
   
        }   
   
    };  
} 

ParcelableActivity1 发送的代码:

package com.androidtest.parcelable;  
   
import android.app.Activity;  
import android.content.Intent;  
import android.os.Bundle;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.LinearLayout;  
public class ParcelableActivity1 extends Activity {  
   
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        // TODO Auto-generated method stub  
        super.onCreate(savedInstanceState);  
        LinearLayout linearLayout = new LinearLayout(this);  
        Button button = new Button(this);  
        button.setText("Send Parcelable Object");  
        linearLayout.addView(button);  
        button.setOnClickListener(new OnClickListener(){  
            @Override  
            public void onClick(View arg0) {  
                ParcelableObject passObject = new ParcelableObject();  
                passObject.setName("Leon Zhang");  
                passObject.setAge(18);  
                passObject.setSurName("xxx");  
   
                Intent intent = new Intent(ParcelableActivity1.this,ParcelableActivity2.class);  
//              使用Bundle发送  
//              Bundle bundle = new Bundle();  
//              bundle.putParcelable("key", passObject);  
                intent.putExtra("key", passObject);  
//              intent.putExtras(bundle);  
                intent.putExtra("key2", "out of bundle");  
                startActivity(intent);  
            }  
        });  
       this.setContentView(linearLayout);  
    }  
   
} 

ParcelableActivity2 接收的代码:

package com.androidtest.parcelable;  
   
import android.app.Activity;  
import android.os.Bundle;  
import android.util.Log;  
   
public class ParcelableActivity2 extends Activity {  
   
    private static final String TAG = ParcelableActivity2.class.getSimpleName();  
   
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
   
        // TODO Auto-generated method stub  
        super.onCreate(savedInstanceState);  
        ParcelableObject passObject = this.getIntent()  
                .getParcelableExtra("key");  
   
        Log.v(TAG, "Name: " + passObject.getName() + " Surname: "  
                        + passObject.getSurName() + " Age: "  
                        + String.valueOf(passObject.getAge())  
                        + " out of bundle is :"  
                        + this.getIntent().getStringExtra("key2"));  
        Bundle myBundle = this.getIntent().getExtras();  
        Log.v(TAG,"XX: "  
                        + ((ParcelableObject) myBundle.getParcelable("key"))  
                                .getName()+ " Key2 :"+ myBundle.getString("key2"));  
   
    }  
   
} 

经过测试发现,当使用Intent传递数据时,如果你自己创建了一个Bundle,则无论要传的数据是否放入Bundle(如直接intent.putExtra("xx" , "xx")),都会放到放到此Bundle中。如果没有创建此Bundle,则会默认创建一个Bundle来存放数据。当取数据时可以先取Bundle再从Bundle中取数据,或者直接取就好了。

 

参考:

http://zuiniuwang.blog.51cto.com/3709988/718330

http://www.2cto.com/kf/201205/132814.html

http://blog.csdn.net/dairyman000/article/details/7247619

posted on 2012-10-06 08:01  子墨苑  阅读(892)  评论(0编辑  收藏  举报