その時に状態を保存しておき、再作成後に復帰させる。
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.CreatorCREATOR = new Parcelable.Creator () { public SavedState createFromParcel(Parcel source) { return new SavedState(source); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; }