Android开发之漫漫长途 X——Android序列化 (2)

相对于Serializable而言,Parcelable的使用要复杂一些

public class Book implements Parcelable { private String name; public Book(String name) { this.name = name; } protected Book(Parcel in) { name = in.readString(); } //反序列化功能由CREATOR完成,在CREATOR的内部标明的如何创建序列对象和数组 public static final Creator<Book> CREATOR = new Creator<Book>() { //从Parcel中反序列化对象 @Override public Book createFromParcel(Parcel in) { //其内部调用Parcel的一系列readXXX方法实现反序列化过程 return new Book(in); } //创建序列化数组 @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public int describeContents() { return 0; } //序列化过程: //重写writeToParcel方法,我们要在这里逐一对需要序列化的属性用Parcel的一系列writeXXX方法写入 @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); } }

从上述代码注释可以看出,写一个实现Parcelable接口的类还是比较麻烦的,和Serailable相比,我们需要在writeToParcel中按序写入各个域到流中,同样,在createFromParcel中我们需要自己返回一个Book对象。

Parcelable在使用上也与Serializable稍有不同

public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test2); //获取一个Parcel容器 Parcel parcel = Parcel.obtain(); //需要序列化的对象 Book book = new Book("c++"); //把对象写入Parcel parcel.writeParcelable(book,0); //Parcel读写共用一个位置计数,这里一定要重置一下当前的位置 parcel.setDataPosition(0); //读取Parcel Book book1 = parcel.readParcelable(Book.class.getClassLoader()); Log.d("TestActivity",book1.toString()); } } Parcelable的写

我们来看一下writeParcelable方法
[Parcel.java]

public final void writeParcelable(Parcelable p, int parcelableFlags) { //判断p是否为空 if (p == null) { writeString(null); return; } //① 先写入p的类名 writeParcelableCreator(p); //② 调用我们重写的writeToParcel方法,按顺序写入域 p.writeToParcel(this, parcelableFlags); } public final void writeParcelableCreator(Parcelable p) { //① 先写入p的类名 String name = p.getClass().getName(); writeString(name); } Parcelable的读

我们来看readParcelable方法
[Parcel.java]

public final <T extends Parcelable> T readParcelable(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(ClassLoader loader) { //首先把类名读取出来 String name = readString(); Parcelable.Creator<?> creator; //mCreators做了一下缓存,如果之前某个classloader把一个parcelable的Creator获取过 //那么就不需要通过反射去查找了 synchronized (mCreators) { HashMap<String,Parcelable.Creator<?>> map = mCreators.get(loader); if (map == null) { map = new HashMap<>(); mCreators.put(loader, map); } creator = map.get(name); if (creator == null) { try { ClassLoader parcelableClassLoader = (loader == null ? getClass().getClassLoader() : loader); //加载我们自己实现Parcelable接口的类 Class<?> parcelableClass = Class.forName(name, false, parcelableClassLoader); Field f = parcelableClass.getField("CREATOR"); Class<?> creatorType = f.getType(); creator = (Parcelable.Creator<?>) f.get(null); } catch (Exception e) { //catch exception } 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; }

我们的测试例子读取Parcel

Book book1 = parcel.readParcelable(Book.class.getClassLoader());

可以看到我们在使用
readParcelable的时候,传入的参数是Book类的类加载器,根据我们上面的代码,我们知道我们先会通过反射获取定义在Book类中的CREATOR属性,我们回想一下在Book类中是怎么定义CREATOR的

public static final Creator<Book> CREATOR = new Creator<Book>() { //从Parcel中反序列化对象 @Override public Book createFromParcel(Parcel in) { //其内部调用Parcel的一系列readXXX方法实现反序列化过程 return new Book(in); } //创建序列化数组 @Override public Book[] newArray(int size) { return new Book[size]; } };

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwgsp.html