小包の包み方
createFromParcelメソッドからして、非直列化はこのインタフェースを介して行うらしいが、どうしてこんな作りになっているんだろう。
前にも書いたが、Androidではアプリケーション(ActivityやService)間が分離されており、オブジェクトやデータを共有することできないので、何らかのメッセージ通信のメカニズムが必要になる。
AndroidはIntent(インテント)という簡易なプロセス間通信(Windowsで言うところのDDEに近い)のメカニズムを実装しており、ParcelクラスはParcelableを含む、Androidアプリケーション間で通信するオブジェクトをインテントを介して直列/非直列化する。
実際のParcelクラス中、Parcelableを読込むためのreadParcelableメソッドを見てみよう。
- Parcel#readParcelable
public finalT readParcelable(ClassLoader loader) { String name = readString(); if (name == null) { return null; } Parcelable.Creator 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 { Class c = loader == null ? Class.forName(name) : Class.forName(name, true, loader); Field f = c.getField("CREATOR"); creator = (Parcelable.Creator)f.get(null); } catch (IllegalAccessException e) { Log.e("Parcel", "Class not found when unmarshalling: " + name + ", e: " + e); : : return creator.createFromParcel(this); :
Parcelableの実装クラスに"CREATOR"という名でParcelable.Creator
前回のエントリで話題にしたKeyEventクラスを見てみよう。
- android.view.KeyEvent.CREATOR
public static final Parcelable.CreatorCREATOR = new Parcelable.Creator () { public KeyEvent createFromParcel(Parcel in) { return new KeyEvent(in); } public KeyEvent[] newArray(int size) { return new KeyEvent[size]; } }; 〜 private KeyEvent(Parcel in) { mAction = in.readInt(); mKeyCode = in.readInt(); mRepeatCount = in.readInt(); mMetaState = in.readInt(); mDeviceId = in.readInt(); mScancode = in.readInt(); mFlags = in.readInt(); mDownTime = in.readLong(); mEventTime = in.readLong(); }
JavaにはSerializableという汎用の直列化の仕組みがあるが、基本的に使う側の責任において実装するものであり、外部から全面的にはその実装を信用できない。また、配列やリストを普通に直列化/非直列化することは非常に効率が悪いので、Androidはそれを嫌い、Parcelableという仕組みを用意したのだろう、と勝手に妄想。
やっぱりソースコードを読めるってことはいいなぁ。ドキュメントが完全に邦訳されないうちはソースコードが一番のドキュメントだ。