前面我们知道了启动activity的时候可以传递一些参数。Activity的跳转时可以传递Parcelable对象。
Parcelable对象和Serializable不一样。实现了Parcelable接口的类并不会被系统序列化。
接下来我们用一个例子看看如何使用这一接口。
使用例子
先准备数据,然后传送Parcelable对象。
数据准备
先设计一个类实现Parcelable接口。前面我们使用Serializable的时候,类只要实现Serializable接口即可,不需要额外的操作。但用Parcelable接口会需要开发者多做一些工作。
Parcelable接口在android.os
包里,与Serializable不同。我们必须明确认识这一点。
官方给出的一个使用例子。
public class MyParcelable implements Parcelable {
private int mData;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}
public static final Parcelable.Creator<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
private MyParcelable(Parcel in) {
mData = in.readInt();
}
}
可以看到,强制使用了一个Parcelable.Creator
对象。里面的方法我们暂时不管也不修改。
重点关注私有构造器MyParcelable(Parcel in
和writeToParcel
方法。
官方例子中,私有构造器接收一个Parcel对象,然后从中读出一个int。而writeToParcel
方法中,把mData写入Parcel对象中。
这写入和读出操作就是我们开发者需要特别关心的地方。
之前使用intent.putExtra方法的时候会传入一个String类型的key(键),用于标示传入的数据。
但在官方的例子中,我们只看到了一个int。而writeInt方法也没有指定key。系统如何区分出各个参数呢?
我们自定义一个类DataParcel
,实现Parcelable
接口。as自动在里面生成了CREATOR。
import android.os.Parcel;
import android.os.Parcelable;
public class DataParcel implements Parcelable {
private int number;
private String str1;
private String str2;
private String noSave = "[不传送的字符串]";
// getter setter ...
public String info() {
return "number: "+number+", str1: "+str1+", str2: "+str2+", noSave: "+noSave;
}
protected DataParcel(Parcel in) {
number = in.readInt();
str1 = in.readString();
str2 = in.readString();
}
public DataParcel(int number, String str1, String str2, String noSave) {
this.number = number;
this.str1 = str1;
this.str2 = str2;
this.noSave = noSave;
}
public static final Creator<DataParcel> CREATOR = new Creator<DataParcel>() {
@Override
public DataParcel createFromParcel(Parcel in) {
return new DataParcel(in);
}
@Override
public DataParcel[] newArray(int size) {
return new DataParcel[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(number);
dest.writeString(str1);
dest.writeString(str2);
}
}
可以看到我们有1个int和3个String。公开构造器需要传入这4个属性。
writeToParcel
方法中,按顺序写入了int和2个String。私有构造器中,按顺序读出了int和2个String。
noSave
并没有被写入和读出。拿来做对比。info()
方法是拿来打印信息的。
传送Parcelable对象
现在我们的类已经设计好了,传送对象试试。
把DataParcel对象交给intent。
DataParcel dataParcel = new DataParcel(100, "s1", "s2", "改变这个字符串看看能否被传递");
intent.putExtra(SendParamsDemo.K_PARCEL, dataParcel);
被打开的Activity接收传入的对象。
DataParcel dataParcel = intent.getParcelableExtra(K_PARCEL);
log中打印出发送和传入的对象信息。
D/rustAppMainActivity: goSendParamsDemo: parcel obj: com.rustfisher.tutorial2020.act.DataParcel@d8ce985
D/rustAppMainActivity: goSendParamsDemo: parcel obj: number: 100, str1: s1, str2: s2, noSave: 改变这个字符串看看能否被传递
D/rustAppSendParamsDemo: gotInput: parcel obj: com.rustfisher.tutorial2020.act.DataParcel@d90a3a6
D/rustAppSendParamsDemo: gotInput: number: 100, str1: s1, str2: s2, noSave: [不传送的字符串]
从log中我们可以看出,发送的对象和接收到的对象并不是同一个对象。但我们指定的那3个属性是相同的。
总结
至此,我们了解了如何使用Parcelable这个接口。
Parcel和Parcelable是Android IPC中使用到的容器和工具。大家可以了解一下Binder机制
一般认为,普通情况下Parcelable性能上会优于Serializable。
Serializable涉及到序列化,系统会通过反射的方法来获取信息。相对而言比较耗资源。
Parcel并不涉及序列化机制。它是为了高性能IPC传输设计的。因此,Parcel并不适合用来永久化存储数据。
实际工作中,我们可以根据业务需要,综合开发时间成本和应用性能要求,来选择使用Parcelable或者Serializable。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。