その時に状態を保存しておき、再作成後に復帰させる。
ActivityのonSaveInstanceState(Bundle) を使う方法は随所で解説されているが、カスタムView側で保存する方法もあったのでメモ。
状態の保存は、View.onSaveInstanceStateをオーバーライドして行う。
このメソッドは、状態を保存したParcelableオブジェクトを返す。
状態の復元は、View.onRestoreInstanceStateをオーバーライドして行う。
onSaveInstanceStateで保存したParcelableを引数で渡してくれるので、適宜復元する。
Parcelableオブジェクトは、Bundleでも動作するが、TextViewやAbsListViewではView.BaseSavedStateを継承して独自クラスを作っている。どれが推奨されているかは不明。
注意点としては、内部的に、ViewのIDをキーとしてParcelableが保存されるので、
ViewのIDが無いと保存できないことと、必ず一意にしておくこと。
もしIDが重複していると、最後に実行したonSaveInstanceStateの情報しか保存されない。
これはスタイル属性全般の注意点だが、カスタムViewを作成した時に、
コンストラクタで渡されたAttributeSetをそのまま子ビューに渡すと、スタイル属性が全て子ビューに渡ってしまう。
そのため、もし放置しておくと、自分自身と子Viewの全てが同じIDを持つことになってしまう。
この状態になると、当然だがonSaveInstanceStateはマトモに機能しない。
このスタイル属性からのID重複で丸一日ハマった・・・。
サンプルコードはこんな感じ。ソースをまんま貼り付けると、えらく間延びするなぁ。
/**
* 画面の向きの変更時など、オブジェクトが再作成される時に状態を保存する
* @see android.view.View#onSaveInstanceState()
*/
@Override
protected Parcelable onSaveInstanceState()
{
Parcelable parent = super.onSaveInstanceState();
/*
* BaseSavedState拡張版
*/
{
SavedState saved = new SavedState(parent);
saved.first = 1;
saved.second = "Test";
saved.third = true;
return saved;
}
/*
* Bundle版。クラス実装が不要なので手軽?
*/
// {
// Bundle b = new Bundle();
//
// b.putParcelable("Parent", parent);
// b.putString("myData", "myData");
//
// return b;
// }
}
/**
* onSaveInstanceStateで保存した状態を復元する
* @see android.view.View#onRestoreInstanceState(android.os.Parcelable)
*/
@Override
protected void onRestoreInstanceState(Parcelable state)
{
/*
* BaseSavedState拡張版の復元
*/
{
if(!(state instanceof SavedState))
return;
SavedState saved = (SavedState)state;
super.onRestoreInstanceState(saved.getSuperState());
int first = saved.first;
String second = saved.second;
boolean third = saved.third;
}
/*
* Bundle版の復元
*/
// {
// if(!(state instanceof Bundle))
// return;
//
// Bundle b = (Bundle)state;
//
// super.onRestoreInstanceState(b.getParcelable("Parent"));
// String s = b.getString("myData");
// }
}
/**
* onSaveInstanceStateで保存する状態を保持するためのクラス
*/
public static class SavedState extends View.BaseSavedState
{
private int first;
private String second;
private boolean third;
/**
* Parcelから状態を復元するためのコンストラクタ
*/
public SavedState(Parcel in)
{
/*
* 必ず書いた順序で読み込むこと!
*/
super(in);
first = in.readInt();
second = in.readString();
third = in.readInt() == 0 ? false : true;
}
/**
* 状態の保存用コンストラクタ
*/
public SavedState(Parcelable superState)
{
super(superState);
}
/**
* Parcelにデータを書き込む
* @see android.view.AbsSavedState#writeToParcel(android.os.Parcel, int)
*/
@Override
public void writeToParcel(Parcel out, int flags)
{
super.writeToParcel(out, flags);
out.writeInt(first);
out.writeString(second);
// booleanはそのまま書けないので、intなどに変換する
out.writeInt(third ? 1 : 0);
}
/**
* Parcelableの仕様で、ファクトリの実装が必要
*/
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator()
{
public SavedState createFromParcel(Parcel source)
{
return new SavedState(source);
}
public SavedState[] newArray(int size)
{
return new SavedState[size];
}
};
}

