Activity之间传数据时,为了避免麻烦,往往会将一些值封装成对象,然后将整个对象传递过去。
对于Android来说传递复杂类型,主要是将自己的类转换为基础的字节数组,Activity之间传递数据是通过Intent实现的。
Android序列化对象主要有两种方法,实现Serializable接口、或者实现Parcelable接口。实现Serializable接口是Java SE本身就支持
的,而Parcelable是Android特有的功能,效率比实现Serializable接口高,而且还可以用在进程间通信(IPC)中。
实现Serializable接口非常简单,声明一下就可以了。而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。
什么时候使用序列化?
a)当你想把的内存中的对象写入到硬盘的时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;
再稍微解释一下:
a)比如说你的内存不够用了,那计算机就要将内存里面的一部分对象暂时的保存到硬盘中,等到要用的时候再读入到
内存中,硬盘的那部分存储空间就是所谓的虚拟内存。在比如过你要将某个特定的对象保存到文件中,我隔几天在把
它拿出来用,那么这时候就要实现Serializable接口;
b)在进行java的Socket编程的时候,你有时候可能要传输某一类的对象,那么也就要实现Serializable接口;
最常见的你传输一个字符串,它是JDK里面的类,也实现了Serializable接口,所以可以在网络上传输。
c)如果要通过远程的方法调用(RMI)去调用一个远程对象的方法,如在计算机A中调用另一台计算机B的对象的方法,
那么你需要通过JNDI服务获取计算机B目标对象的引用,将对象从B传送到A,就需要实现序列化接口。
1、什么是Parcelable接口呢?
1)Parcelable,定义了将数据写入Parcel,和从Parcel中读出的接口。一个实体(用类来表示),如果需要封装到消息中去,就必须实现这一接口,实现了这一接口,该实体就成为“可打包的”了。
2)Parcelable接口的定义:
public interface Parcelable { //内容描述接口,基本不用管 public int describeContents(); //写入接口函数,打包 public void writeToParcel(Parcel dest, int flags); //读取接口,目的是要从Parcel中构造一个实现了Parcelable的类的实例处理。因为实现类在这里还是不可知的,所以需要用到模板的方式, <span style="font-family:Arial;"> </span>//继承类名通过模板参数传入。 //为了能够实现模板参数的传入,这里定义Creator嵌入接口,内含两个接口函数分别返回单个和多个继承类实例。 public interface Creator<T> { public T createFromParcel(Parcel source); public T[] newArray(int size); } }
二 至于选取哪种可参考下面的原则:
1.在使用内存的时候,Parcelable 类比Serializable性能高,所以推荐使用Parcelable类。
2.Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3.Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点, 也不提倡用,但在这种情况下,还是建议你用Serializable 。
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从流里读取对象,只不过这个过程
需要你来实现,因此写的顺序和读的顺序必须一致。
示例代码:
package com.yang.domain; import android.os.Parcel; import android.os.Parcelable; public class Person implements Parcelable { //这里定义了两个变量来说明读和写的顺序要一致 private Integer id; private String name; public Person() { } public Person(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { // 把javanbean中的数据写到Parcel。先写id然后写name dest.writeInt(this.id); dest.writeString(this.name); } // 添加一个静态成员,名为CREATOR,该对象实现了Parcelable.Creator接口 public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() { @Override public Person createFromParcel(Parcel source) { // 从Parcel中读取数据,返回person对象 return new Person(source.readInt(), source.readString()); } @Override public Person[] newArray(int size) { return new Person[size]; } }; }
public class MyParcelable implements Parcelable { private List<MyListClass> arrList = new ArrayList<MyListClass>(); private int myInt = 0; private String str = null; public String getStr() { return str; } public void setStr(String str) { this.str = str; } public List<MyListClass> getArrList() { return arrList; } public void setArrList(List<MyListClass> arrList) { this.arrList = arrList; } public int getMyInt() { return myInt; } public void setMyInt(int myInt) { this.myInt = myInt; } MyParcelable() { // initialization arrList = new ArrayList<MyListClass>(); } public MyParcelable(Parcel in) { myInt = in.readInt(); str = in.readString(); in.readTypedList(arrList, MyListClass.CREATOR); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel outParcel, int flags) { outParcel.writeInt(myInt); outParcel.writeString(str); outParcel.writeTypedList(arrList); } public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() { @Override public MyParcelable createFromParcel(Parcel in) { return new MyParcelable(in); } @Override public MyParcelable[] newArray(int size) { return new MyParcelable[size]; } }; }当有子类父类情况时:
public abstract class A implements Parcelable { private int a; protected A(int a) { this.a = a; } public void writeToParcel(Parcel out, int flags) { out.writeInt(a); } protected A(Parcel in) { a = in.readInt(); } } public class B extends A { private int b; public B(int a, int b) { super(a); this.b = b; } public static final Parcelable.Creator<B> CREATOR = new Parcelable.Creator<B>() { public B createFromParcel(Parcel in) { return new B(in); } public B[] newArray(int size) { return new B[size]; } }; public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(b); } private B(Parcel in) { super(in); b = in.readInt(); } }
1)一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。而实际上,Serializable是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化。
2)如何实现Serializable接口?
很简单,只要implements Serializable接口就可以了
3)代码实现>
package com.jyxp.my.parcelable; import java.io.Serializable; public class MySerializable implements Serializable { private static final long serialVersionUID = 1L; private Double mDouble; private Float mFloat; public MySerializable() { // TODO Auto-generated constructor stub } public Double getmDouble() { return mDouble; } public void setmDouble(Double mDouble) { this.mDouble = mDouble; } public Float getmFloat() { return mFloat; } public void setmFloat(Float mFloat) { this.mFloat = mFloat; } }
1)基本数据类型,自身可以
2)传递Serializable对象时,被传递的Serializable对象里面的自定义成员对象(非API中的Serializable对象)也要实现
Serializable接口,否则会出现Caused by: java.io.NotSerializableException异常。从上面的代码可以看出,
在Parcelable对象中是可以传递Serializable对象的,但Serializable对象里面传递的时候可不可以有Parcelable?
回答是否定的,一样会产生java.io.NotSerializableException异常.
3)android api中只能传递Parcelable对象的集合,而不能传递Serializable对象的集合,也就是只能传递
ArrayList<Bitmap>,却不能传递ArrayList<Designer>。刚刚开始学android的时候,对象都是被封装成Serializable,
再传递,因为Serializable是JAVASE里面的本地化接口,很熟悉,当时也产生疑问,为什么会有Parcelable接口,
这两个有什么区别?到后来,当Serializable不能满足要求的时候就明白了,android利用Pacelable对自己的东西进行
封装,就像Worker中的Bitmap,在read的时候可以不需要设置ClassLoader。
4)也是可以传递枚举enum的,把枚举当做类来看就行了。