Android中的序列化机制——Parcel与Parcelable
2014-12-01 15:35
369 查看
当我们在调用远程方法时,需要在进程间传递参数以及返回结果。这种类似的处理方式,需要把数据与进程相关性去除,变成一种中间形式,然后按统一的接口进行读写操作。这样的机制,一般在高级编程语言里都被称为序列化。
在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。
2.实现Parcelable就是为了进行序列化,那么,为什么要序列化?
1)永久性保存对象,保存对象的字节序列到本地文件中;
2)通过序列化对象在网络中传递对象;
3)通过序列化在进程间传递对象。
3.实现序列化的方法
Android中实现序列化有两个选择:一是实现Serializable接口(是JavaSE本身就支持的),一是实现Parcelable接口(是Android特有功能,效率比实现Serializable接口高效,可用于Intent数据传递,也可以用于进程间通信(IPC))。实现Serializable接口非常简单,声明一下就可以了,而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。
注:Android中Intent传递对象有两种方法:一是Bundle.putSerializable(Key,Object),另一种是Bundle.putParcelable(Key,Object)。当然这些Object是有一定的条件的,前者是实现了Serializable接口,而后者是实现了Parcelable接口。
4.选择序列化方法的原则
1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
5.应用场景
需要在多个部件(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<Book> CREATOR = new Creator<Book>() { @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(); } }
1、describeContents(),Parcelabl所需要的接口方法之一,必须实现。这一方法作用很简单,就是通过返回的整形来描述这一Parcel是起什么作用的,通过这一整形每个bit来描述其类型,一般会返回0。
2、writeToParcel(),Parcelabl所需要的接口方法之二,必须实现。writeToParcel()方法的作用是发送,就是将类所需要传输的属性写到Parcel里,被用来提供发送功能的Parcel,会作为第一个参数传入,于是在这个方法里都是使用writeInt()、writeLong()写入到Parcel里。这一方法的第二参数是一个flag值,可以用来指定这样的发送是单向还是双向的,可以与aidl的in、out、inout三种限定符匹配。
3、CREATOR对象,Parcelable接口所需要的第三项,必须提供实现,但这是一个是接口对象。正如我们看到的,这一CREATOR对象,是使用模板类Parcelable.Creator,套用到TaskInfo来得到的,Parcelable.Creator<TaskInfo>。这个CREATOR对象在很大程度上是一个工厂(Factory)类,用于远程对象在接收端的创建。从某种意义上来说,writeToParcel()与CREATOR是一一对应的,发送端进程通过writeToParcel(),使用一个Parcel对象将中间结果保存起来,而接收端进程则会使用CREATOR对象把作为Parcel对象的中间对象再恢复出来,通过类的初始化方法以这个Parcel对象为基础来创建新对象。后续的4-6,则是完成这个CREATOR对象的实现。
4、createFromParcel(),这是ParcelableCreator<T>模板类所必须实现的接口方法,提供从Parcel转义出新的对象的能力。接收端来接收传输过来的Parcel对象时,便会以这一个接口方法来取得对象。我们这里直接调用基于Parcel 的类的初始化方法,然后将创建的对象返回。
5、newArray(),这是ParcelableCreator<T>模板类所必须实现的另一个接口方法,但这一方法用于创建多个这种实现了Parcelable接口的类。通过这一方法,CREATOR对象不光能创建单个对象,也能返回多个创建好的空对象,但多个对象不能以某个Parcel对象为基础创建,于是会使用默认的类创始化方法。
6、实现具体的以Parcel为参照的初始化方法,这并非必须,我们也可以在createFromParcel()里直接根据Parcel的值赋值到对象来实现,但这样实现则更清晰。这一方法,基本上与writeToParcel()是成对的,以什么顺序将对象属性写入Parcel,则在createFromParcel()会就会以同样的顺序对象属性从Parcel里读出来,使用Parcel的readInt()、readLong()等方法来完成。
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<MyColor> CREATOR = new Parcelable.Creator<MyColor>() { public MyColor createFromParcel(Parcel in) { return new MyColor(in); } public MyColor[] newArray(int size) { return new MyColor[size]; } }; }
MainActivity的代码:
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"); //<span style="font-size: 14px; white-space: pre;">反序列化后是一个新的MyColor对象</span> 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); } }
SubActivity的代码:
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); } }
在MainActivity的onActivityResult()中,有一句color=data.getParcelableExtra("MyColor"),这说明的是反序列化后是一个新的MyColor对象,因此要想使用这个对象,我们做了这个赋值语句。
如果数据本身是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; }
修改MyColor的代码如下:
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<MyColor> CREATOR = new Parcelable.Creator<MyColor>() { public MyColor createFromParcel(Parcel in) { return new MyColor(in); } public MyColor[] newArray(int size) { return new MyColor[size]; } }; }
去掉MainActivity的onActivityResult()中的color=data.getParcelableExtra("MyColor")一句,变成:
@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()); } } } }
相关文章推荐
- Android基础——序列化机制(实现Parcelable接口)
- 关于Android中的Parcel机制
- Android之Parcelable, Parcel
- android: activity之间传递复杂数据类型[使用Serializable序列化或者Parcelable序列化]
- Android实现Parcelable对象序列化的实例
- Android实现Parcelable对象序列化的实例
- 探索Android中的Parcel机制(上)
- Android开发:使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数
- android之Parcel机制学习
- android 数据传递详解(Serialization、Parcelable、Parcel、Intent、Bundle)
- android 数据传递详解(Serialization、Parcelable、Parcel、Intent、Bundle)
- 探索Android中的Parcel机制
- Android中Parcel机制
- Android Parcel机制
- 安卓学习之--android 数据传递详解(Serialization、Parcelable、Parcel、Intent、Bundle)
- 探索Android中的Parcel机制(上)
- 探索Android中的Parcel机制(上) .
- android 数据传递详解(Serialization、Parcelable、Parcel、Intent、Bundle)
- android 数据传递详解(Serialization、Parcelable、Parcel、Intent、Bundle)
- Android开发:使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数