2010年3月21日日曜日

Android Parcelable を使ってクラスのメンバを一時保存

さて、前回のエントリで、Bundle で状態を保存する方法を
書きました。
Android Bundle で状態を保存

ここでは、Bundle の Method (例えば putString と getString)
を使ってパラメータを保存する方法を紹介しました。

しかーし、ここで問題が発生

「独自にデータクラスを用意していて、このクラスのメンバごと保存したいんだけど…」

さぁ、この場合どうする?

ここで登場するのが Parcelable さんです。

Parcelable はリファレンス
http://developer.android.com/intl/ja/reference/android/os/Parcelable.html
に書いてあるように、Parcel にデータを書き/読みするためのインタフェースです。

"Interface for classes whose instances can be written to and restored from a Parcel. Classes implementing the Parcelable interface must also have a static field called CREATOR, which is an object implementing the Parcelable.Creator interface. "

Parcelable インタフェースを実装したクラスは、Parcelable.Creator インタフェースを実装するオブジェクトである CREATOR と呼ばれる静的フィールドを持たなくてはなりません。

そして、ご丁寧に Parcelable インタフェースを実装するクラスの例が載ってます。


public class MyParcelable implements Parcelable {
private int mData;

public int describeContents() {
return 0;
}

public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}

public static final Parcelable.Creator<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}

public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};

private MyParcelable(Parcel in) {
mData = in.readInt();
}
}



ここでは、Parcel に保存するパラメータとして、mData が1つですが、

例えば、名前、年齢、アドレスをメンバに持つ
クラス(ContactParcelable)を作るとこんな感じになります。



public class ContactParcelable implements Parcelable {
private String name;
private int age;
private String address;

public int describeContents() {
return 0;
}

public void writeToParcel(Parcel out, int flags) {
out.writeString(name);
out.writeInt(age);
out.writeString(address);
}

public static final Parcelable.Creator<ContactParcelable> CREATOR
= new Parcelable.Creator<ContactParcelable>() {
public ContactParcelable createFromParcel(Parcel in) {
return new ContactParcelable(in);
}

public ContactParcelable[] newArray(int size) {
return new ContactParcelable[size];
}
};

private ContactParcelable(Parcel in) {
name = in.readString();
age = in.readInt();
address = in.readString();
}

public ContactParcelable(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
}


writeToParcel(Parcel out, int flags)
で書き込む順番と
ContactParcelable(Parcel in)
で読み出す順番は同じにしなければなりません。

で、このクラスを
onSaveInstanceState(Bundle) で保存し、
onRestoreInstanceState(Bundle)
で読み出すには、こんな感じでOK


ContactParcelable contactParcelable;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

contactParcelable = new ContactParcelable("あんどろいど", 2, "android@gmail.com");
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/* ここで状態を保存 */
outState.putParcelable("contact", contactParcelable);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
/* ここで保存した状態を読み出して設定 */
contactParcelable = savedInstanceState.getParcelable("contact");
}



さらにさらに、
もし、メンバがデータクラスのリストだった場合はどうなるか
この場合も Parcelable を実装します。

ContactParcelable のリストをメンバに持つ AllContactParcelable
を一時保存する場合


public class AllContactParcelable implements Parcelable {

private ArrayList<ContactParcelable> contactList;

public int describeContents() {
return 0;
}

public void writeToParcel(Parcel out, int flags) {
out.writeTypedList(contactList);
}

public static final Parcelable.Creator<AllContactParcelable> CREATOR
= new Parcelable.Creator<AllContactParcelable>() {
public AllContactParcelable createFromParcel(Parcel in) {
return new AllContactParcelable(in);
}

public AllContactParcelable[] newArray(int size) {
return new AllContactParcelable[size];
}
};

private AllContactParcelable(Parcel in) {
contactList = in.createTypedArrayList(ContactParcelable.CREATOR);
}

public AllContactParcelable(ArrayList<ContactParcelable> contactList) {
this.contactList = contactList;
}
}


out.writeTypedList(contactList);
で書き込みし、
contactList = in.createTypedArrayList(ContactParcelable.CREATOR);
で読み出すのがポイント

onSaveInstanceState(Bundle)

onRestoreInstanceState(Bundle)
での実装は同じ



参考ページ
[Android] android.os.Parcelable / Parcel
adakodaさんありがとうございます!

http://developer.android.com/intl/ja/reference/android/os/Bundle.html
http://developer.android.com/intl/ja/reference/android/os/Bundle.html#putParcelable%28java.lang.String,%20android.os.Parcelable%29
http://developer.android.com/intl/ja/reference/android/os/Bundle.html#getParcelable%28java.lang.String%29

0 件のコメント:

コメントを投稿