爲什麼安卓Parcelable接口會有一個內部類Creator

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,優化運行效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章