BaseSaveStateにを拡張してカスタムViewの状態を復元する際の注意点

カスタムViewを作った場合、BaseSaveStateを拡張してViewの状態をカスタムView自身で復元できるようにできます。

この際に注意すべきことが3点あります。

Activityを保持しないを有効にしてチェックする

カスタムViewの復元機能を実装したら、必ず開発者オプションのActivityを保持しないを有効にしてちゃんどう動くかどうか確認しましょう。

自分ではちゃんと実装したつもりでも、これを有効にした状態で画面回転させるとアプリが落ちる場合があります。

フィールド名のタイポに注意

BaseSaveStateを拡張したクラスには、必ずpublic static final Parcelable.Creator<BaseSaveStateを拡張したクラス名> CREATORというフィールドが必要です。

このフィールドの名前はCREATORでなければなりません。

CREATERとタイポすると動きません。動かない上にエラーメッセージはjava.lang.RuntimeException: Unable to start activity ComponentInfo{jp.gcreate.sample.savestatecustomview/jp.gcreate.sample.savestatecustomview.MainActivity2Activity}: java.lang.RuntimeException: Parcel android.os.Parcel@18c09797: Unmarshalling unknown type code 2131296303 at offset 264のように、「フィールド名が違います」と教えてくれません。

writeToParcelで書き出す順番

writeToParcelで書き出す順番とコンストラクタで読み出す順番は同じ順番にしなければなりません。

書き出す順番と読み出す順番が異なるとうまく復元することができません。

順番を同じにすることと一緒に忘れていけないのは、最初にsuperを呼び出すことです。

        public ImageState(Parcel source) {
            super(source);
            savedUri = source.readParcelable(Uri.class.getClassLoader());
        }

        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeParcelable(savedUri, flags);
        }
```

コンストラクタで`super(source)`を最初に呼び出す、`writeToParcel`の最初で`super.writeToParcel(dest, flags)`を呼び出すことも忘れてはいけません。

単純なことですが、エラーメッセージからどこが悪いのか把握しづらいので、知らないとドはまりするので注意しましょう。

## サンプル

public class UriImageView extends ImageView{
 private Uri mUri;

 public UriImageView(Context context, AttributeSet attrs) {
 super(context, attrs);
 setImage();
 }

 private void setImage() {
 if(mUri == null){
 setImageDrawable(getContext().getResources().getDrawable(android.R.drawable.btn_star, getContext().getTheme()));
 }else{
 setImageURI(mUri);
 }
 }

 public void setUri(Uri uri) {
 mUri = uri;
 setImage();
 }

 @Override
 protected Parcelable onSaveInstanceState() {
 Parcelable superState = super.onSaveInstanceState();
 ImageState imageState = new ImageState(superState);
 imageState.savedUri = mUri;
 return imageState;
 }

 @Override
 protected void onRestoreInstanceState(Parcelable state) {
 ImageState imageState = (ImageState) state;
 super.onRestoreInstanceState(imageState.getSuperState());
 setUri(imageState.savedUri);
 requestLayout();
 }

 static class ImageState extends BaseSavedState{
 public static final Parcelable.Creator CREATOR = new Parcelable.Creator(){

 @Override
 public ImageState createFromParcel(Parcel source) {
 return new ImageState(source);
 }

 @Override
 public ImageState[] newArray(int size) {
 return new ImageState[size];
 }
 };
 Uri savedUri;

 public ImageState(Parcel source) {
 super(source);
 savedUri = source.readParcelable(Uri.class.getClassLoader());
 }

 public ImageState(final Parcelable superState) {
 super(superState);
 }

 @Override
 public void writeToParcel(@NonNull Parcel dest, int flags) {
 super.writeToParcel(dest, flags);
 dest.writeParcelable(savedUri, flags);
 }
 }
} “`

Amazonのほしいものリストを公開しています。仕事で欲しいもの、単なる趣味としてほしいもの、リフレッシュのために欲しいものなどを登録しています。 寄贈いただけると泣いて喜びます。大したお礼はできませんが、よりよい情報発信へのモチベーションに繋がりますので、ご検討いただければ幸いです。