BaseSaveStateにを拡張してカスタムViewの状態を復元する際の注意点
カスタムViewを作った場合、BaseSaveStateを拡張してViewの状態をカスタムView自身で復元できるようにできます。
この際に注意すべきことが3点あります。
カスタム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
で書き出す順番とコンストラクタで読み出す順番は同じ順番にしなければなりません。
書き出す順番と読み出す順番が異なるとうまく復元することができません。
順番を同じにすることと一緒に忘れていけないのは、最初に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