Android 序列化Serializable和Parcelable使用和区别
一:Serializable
1.什么是序列化
将一个类对象转换成可存储,可传输状态的过程。
2.什么是Serializable接口
一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才能被序列化。
3.为什么要序列化对象
1.把对象转换为字节序列的过程称为对象的序列化
2.把字节序列恢复为对象的过程称为对象的反序列化
4.序列化用途
1.想把对象的状态信息通过网络进行传输
2.需要把对象持久化存储,存储在文件,数据库等
public class User implements Serializable {
private static final long serialVersionUID = 1L;
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;
}
}
当我跟进去,发现Serializable是一个空接口,一个接口什么都没有,我们可以将它理解成一个标识接口
例如:在课堂上有位学生遇到一个问题,于是举手向老师请教,这时老师帮他解答,那么这位学生的举手其实就是一个标识,自己解决不了问题请教老师帮忙解决。在Java中的这个Serializable接口其实是给jvm看的,通知jvm,我不对这个类做序列化了,你(jvm)帮我序列化就好了。
5.为什么要定义serialVersionUID变量
从说明中可以看出,如果我们没有自己申明一个serialVersionUID变量,接口会默认生成一个serialVersionUID
*但是强烈建议用户自定义一个serialVersionUID,因为默认的serialVersionUID对于class的细节非常敏感,反序列化时可能会导致
InvalidClassException这个异常。*
5.transient关键字
用来表示一个成员变量不是该对象序列化的一部分。当一个对象被序列化的时候,transient型变量的值不包括在序列化结果中。注:static修饰的静态变量天然的就是不可序列化的
private static final long serialVersionUID = 1L;
private String name;
private transient int age;
transient关键字只能修饰变量,而不能修饰方法和类。
被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
二:Parcelable
Parcelable是Android为我们提供的序列化的接口,Parcelable的效率相对于Serializable也高许多。
Parcelable不能使用在要将数据存储在磁盘上情况
在内存中使用Parcelable性能优于Serializable
public class User implements Parcelable {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 从序列化后的对象中创建原始数据*/
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
/**
* 序列化:将当前对象写入序列化结构中
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
/**
* 当前对象的内容描述,存在文件描述符时返回1,其余全返回0
*/
@Override
public int describeContents() {
return 0;
}
/**
* 反序列化
*/
public static final Creator CREATOR = new Creator() {
/**
* 将序列化对象中创建原始数据*/
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
/**
* 创建指定长度的原始对象数组*/
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public String toString() {
return "User{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
1.Parcel英文译为包裹,Android采用这个词表示封装消息的数据。这个通过IBinder通信的消息载体。Parcel用来存放数据的内存(RAM),而不是永久介质。
//获取一个Parcel容器
Parcel parcel=Parcel.obtain();
//需要序列化的对象
User user=new User("mike",13);
//把对象写入Parcel
parcel.writeParcelable(user,0);
//Parcel读写共用一个位置计数,这里一定要重置一下当前的位置
parcel.setDataPosition(0);
//读取Parcel
User user1=parcel.readParcelable(User.class.getClassLoader());
Log.d("LoginActivity",user1.toString());
调用parcel.writeParcelable(user,0);源码解析
public final void writeParcelable(@Nullable Parcelable p, int parcelableFlags) {
//判断p是否为空
if (p == null) {
writeString(null);
return; }
//先写入P的类名(user就是p类类名)
writeParcelableCreator(p);
//调用我们重写的writeToParcel方法,按顺序写入
p.writeToParcel(this, parcelableFlags);
}
/** @hide */
@UnsupportedAppUsage
public final void writeParcelableCreator(@NonNull Parcelable p) {
//写入p类的类名
String name = p.getClass().getName();
writeString(name);
}
调用parcel.readParcelable(User.class.getClassLoader());源码解析
public final T readParcelable(@Nullable ClassLoader loader) {
//调用readParcelableCreator
//这时我们获取就是我们自定义的CREATOR
Parcelable.Creator> creator = readParcelableCreator(loader);
if (creator == null) {
return null;
}
// 判断当前creator是不是Parcelable.ClassLoaderCreator>的实例
if (creator instanceof Parcelable.ClassLoaderCreator>) {
//如果是的话,,我们调用reateFromParcel(this, loader)
Parcelable.ClassLoaderCreator> classLoaderCreator =
(Parcelable.ClassLoaderCreator>) creator;
return (T) classLoaderCreator.createFromParcel(this, loader);
}
//调用我们自定义的CREATOR中重写的createFromParcel方法
return (T) creator.createFromParcel(this);
}
public final Parcelable.Creator> readParcelableCreator(@Nullable ClassLoader loader) {
//首先把类名读取出来
String name = readString();
if (name == null) {
return null;
}
Parcelable.Creator> creator;
//mCreators做了一下缓存,如果之前某个classloader把一个parcelable的Creator获取过
//那么就不需要通过反射去查找了
synchronized (mCreators) {
HashMap> map = mCreators.get(loader);
if (map == null) {
map = new HashMap<>();
mCreators.put(loader, map);
}
creator = map.get(name);
if (creator == null) {
try {
// If loader == null, explicitly emulate Class.forName(String) "caller
// classloader" behavior. ClassLoader parcelableClassLoader =
(loader == null ? getClass().getClassLoader() : loader);
// Avoid initializing the Parcelable class until we know it implements
// Parcelable and has the necessary CREATOR field. http://b/1171613. Class> parcelableClass = Class.forName(name, false /* initialize */,
parcelableClassLoader);
if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
throw new BadParcelableException("Parcelable protocol requires subclassing "
+ "from Parcelable on class " + name);
}
Field f = parcelableClass.getField("CREATOR");
if ((f.getModifiers() & Modifier.STATIC) == 0) {
throw new BadParcelableException("Parcelable protocol requires "
+ "the CREATOR object to be static on class " + name);
}
Class> creatorType = f.getType();
if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {
// Fail before calling Field.get(), not after, to avoid initializing
// parcelableClass unnecessarily. throw new BadParcelableException("Parcelable protocol requires a "
+ "Parcelable.Creator object called "
+ "CREATOR on class " + name);
}
creator = (Parcelable.Creator>) f.get(null);
}
catch (IllegalAccessException e) {
Log.e(TAG, "Illegal access when unmarshalling: " + name, e);
throw new BadParcelableException(
"IllegalAccessException when unmarshalling: " + name);
}
catch (ClassNotFoundException e) {
Log.e(TAG, "Class not found when unmarshalling: " + name, e);
throw new BadParcelableException(
"ClassNotFoundException when unmarshalling: " + name);
}
catch (NoSuchFieldException e) {
throw new BadParcelableException("Parcelable protocol requires a "
+ "Parcelable.Creator object called "
+ "CREATOR on class " + name);
}
if (creator == null) {
throw new BadParcelableException("Parcelable protocol requires a "
+ "non-null Parcelable.Creator object called "
+ "CREATOR on class " + name);
}
map.put(name, creator);
}
}
return creator;
}