Parcelable接口是實現序列化的一種方式,與Serializable相比比較複雜,但勝在運行效率高,在安卓中得到了廣泛應用。主要需要實現寫入和讀出兩個功能,寫入比較易懂,使用 writeToParcel,讀出按說也應該是一個方法createFromParcel,但是卻將其封裝在了Creator類中,這是何故?深入Parcel類的readParcelable方法初步瞭解讀出過程才恍然大悟。
public class User implements Parcelable{
public int userId;
public String userName;
public boolean isMale;
public Book book;
public User(int userId,String userName,boolean isMale){
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
public int describeContents(){
return 0;
}
public void writeToParcel(Parcel out,int flag){
out.writeInt(userId);
out.writeString(userName);
out.writeBoolean(isMale);
out.writeParcelable(book,0);
}
//把createFromParcel方法封裝進Creator類
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>(){
public User createFromParcel(Parcel in){
return new User(in);
}
public User[] newArray(int size){
return new User[size];
}
}
private User(Parcel in){
userId = in.readInt();
userName = in.readString();
isMale = in.readBoolean();
book = in.readParcelable(Thread.currentThread().getContextClassLoader());
}
}
以下是Parcel類中關於讀出的幾個方法
public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
Parcelable.Creator<?> creator = readParcelableCreator(loader);//進入
if (creator == null) {
return null;
}
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
Parcelable.ClassLoaderCreator<?> classLoaderCreator =
(Parcelable.ClassLoaderCreator<?>) creator;
return (T) classLoaderCreator.createFromParcel(this, loader);
}
return (T) creator.createFromParcel(this);
}
public final Parcelable.Creator<?> readParcelableCreator(ClassLoader loader) {
String name = readString();//獲取類名
if (name == null) {
return null;
}
Parcelable.Creator<?> creator;
synchronized (mCreators) {
//設立一個Map存儲Creator,也就是存儲讀出方法
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 {
// 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.
//反射獲得Creator類
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);//因爲是靜態的,所以傳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);//保存creator
}
}
return creator;
}
Parcel的讀寫方法繼續深入就是C語言了,在C語言層面不存在Java的類和方法,所以傳遞信息通過字符串或者其他方法,在讀取時是從C讀到Java,首先通過Class.forName()獲得User的Class類ParcelableClass,再通過ParcelableClass.getField("CREATOR")獲得Creator屬性f,最後通過f.get(null)獲得屬性f的具體實例CREATOR。爲了提高效率避免每次都要獲取一遍,就把結果CREATOR存到map中,下一次可以先在map中查找,沒有再反射獲取。所以Creator的意義在於保存createFromParcel,優化運行效率。