当我们在调用远程方法时,需要在进程间传递参数以及返回结果。这种类似的处理方式,需要把数据与进程相关性去除,变成一种中间形式,然后按统一的接口进行读写操作。这样的机制,一般在高级编程语言里都被称为序列化。
在Android世界里处理数据的序列化操作的,使用了一种Parcel类,而能够处理数据序列能力,则是实现Parcelable接口来实现。于是,当我们需要在进程间传输一个对象,则实现这一对象的类必须实现Parcelable接口里定义的相应属性或方法,而在使用这一对象时,则可以使用一个Parcel引用来处理传输时的基本操作。
Parcel和Serialize很类似,只是它是在内存中完成的序列化和反序列化,利用的是连续的内存空间,因此会更加高效。
1. Parcelable接口
Interface for classes whose instances can be written to and restored from a Parcel。 Classes implementing the Parcelable interface must also have a static field called CREATOR, which is an object implementing the Parcelable.Creator interface。需要在多个部件(Activity或Service)之间通过Intent传递一些数据,简单类型(如:数字、字符串)的可以直接放入Intent。复杂类型必须实现Parcelable接口。
6.Serializable实现与Parcelabel实现的区别
1)Serializable的实现,只需要implements Serializable 即可。这只是给对象打了一个标记,系统会自动将其序列化。
2)Parcelabel的实现,不仅需要implements Parcelabel,还需要在类中添加一个静态成员变量CREATOR,这个变量需要实现 Parcelable.Creator 接口。
1)创建Person类,实现Serializable:
public class Person implements Serializable
{
private static final long serialVersionUID = -7060210544600464481L;
private String name;
private int age;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
2)创建Book类,实现Parcelable:
public class Book implements Parcelable
{
private String bookName;
private String author;
private int publishDate;
public Book()
{
}
public String getBookName()
{
return bookName;
}
public void setBookName(String bookName)
{
this.bookName = bookName;
}
public String getAuthor()
{
return author;
}
public void setAuthor(String author)
{
this.author = author;
}
public int getPublishDate()
{
return publishDate;
}
public void setPublishDate(int publishDate)
{
this.publishDate = publishDate;
}
@Override
public int describeContents()
{
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags)
{
out.writeString(bookName);
out.writeString(author);
out.writeInt(publishDate);
}
public static final Parcelable.Creator CREATOR = new Creator()
{
@Override
public Book[] newArray(int size)
{
return new Book[size];
}
@Override
public Book createFromParcel(Parcel in)
{
return new Book(in);
}
};
public Book(Parcel in)
{
bookName = in.readString();
author = in.readString();
publishDate = in.readInt();
}
}
7.应用实例
就应用程序而言,最常见使用Parcel类的场景就是在Activity间传递数据。没错,在Activity间使用Intent传递数据的时候,可以通过Parcelable机制传递复杂的对象。
在下面的程序中,MyColor用于保存一个颜色值,MainActivity在用户点击屏幕时将MyColor对象设成红色,传递到SubActivity中,此时SubActivity的TextView显示为红色的背景;当点击SubActivity时,将颜色值改为绿色,返回MainActivity,期望的是MainActivity的TextView显示绿色背景。
MyColor类的实现代码:
package com.test;
import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;
public class MyColor implements Parcelable {
private int color=Color.BLACK;
MyColor(){
color=Color.BLACK;
}
MyColor(Parcel in){
color=in.readInt();
}
public int getColor(){
return color;
}
public void setColor(int color){
this.color=color;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(color);
}
public static final Parcelable.Creator CREATOR
= new Parcelable.Creator() {
public MyColor createFromParcel(Parcel in) {
return new MyColor(in);
}
public MyColor[] newArray(int size) {
return new MyColor[size];
}
};
}
package com.test;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
public class MainActivity extends Activity {
private final int SUB_ACTIVITY=0;
private MyColor color=new MyColor();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==SUB_ACTIVITY){
if (resultCode==RESULT_OK){
if (data.hasExtra("MyColor")){
color=data.getParcelableExtra("MyColor"); //反序列化后是一个新的MyColor对象
findViewById(R.id.text).setBackgroundColor(color.getColor());
}
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event){
if (event.getAction()==MotionEvent.ACTION_UP){
Intent intent=new Intent();
intent.setClass(this, SubActivity.class);
color.setColor(Color.RED);
intent.putExtra("MyColor", color);
startActivityForResult(intent,SUB_ACTIVITY);
}
return super.onTouchEvent(event);
}
}
package com.test;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.TextView;
public class SubActivity extends Activity {
private MyColor color;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((TextView)findViewById(R.id.text)).setText("SubActivity");
Intent intent=getIntent();
if (intent!=null){
if (intent.hasExtra("MyColor")){
color=intent.getParcelableExtra("MyColor");
findViewById(R.id.text).setBackgroundColor(color.getColor());
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event){
if (event.getAction()==MotionEvent.ACTION_UP){
Intent intent=new Intent();
if (color!=null){
color.setColor(Color.GREEN);
intent.putExtra("MyColor", color);
}
setResult(RESULT_OK,intent);
finish();
}
return super.onTouchEvent(event);
}
}
如果数据本身是IBinder类型,那么反序列化的结果就是原对象,而不是新建的对象,很显然,如果是这样的话,在反序列化后在MainActivity中就不再需要color=data.getParcelableExtra("MyColor")这句了。因此,换一种MyColor的实现方法,令其中的int color成员变量使用IBinder类型的成员变量来表示。
新建一个BinderData类继承自Binder,代码如下:
package com.test;
import android.os.Binder;
public class BinderData extends Binder {
public int color;
}
package com.test;
import android.graphics.Color;
import android.os.Parcel;
import android.os.Parcelable;
public class MyColor implements Parcelable {
private BinderData data=new BinderData();
MyColor(){
data.color=Color.BLACK;
}
MyColor(Parcel in){
data=(BinderData) in.readValue(BinderData.class.getClassLoader());
}
public int getColor(){
return data.color;
}
public void setColor(int color){
data.color=color;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(data);
}
public static final Parcelable.Creator CREATOR
= new Parcelable.Creator() {
public MyColor createFromParcel(Parcel in) {
return new MyColor(in);
}
public MyColor[] newArray(int size) {
return new MyColor[size];
}
};
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode==SUB_ACTIVITY){
if (resultCode==RESULT_OK){
if (data.hasExtra("MyColor")){
findViewById(R.id.text).setBackgroundColor(color.getColor());
}
}
}
}