You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义View无法保存状态求助(附StampView代码片段)

我来帮你搞定这个自定义View状态保存的问题!你的代码目前缺少了Android View状态保存的核心实现逻辑,这就是状态无法留存的原因。咱们一步步来修复:

核心问题分析

Android系统只会自动保存View的基础状态(比如EditText的文本),自定义View的状态必须手动实现onSaveInstanceState()和onRestoreInstanceState(),还要正确处理父类的状态,同时把自定义状态打包到SavedState中。另外,别忘了给你的StampView在布局里设置android:id——没有ID的话,系统会跳过它的状态保存流程哦!

完整修复后的代码示例
public class StampView extends View {
    // View State items
    private String stampText, stampTimeStamp;
    private int stampIconId;
    private boolean stamped;

    public StampView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        // 这里保留你原来的初始化逻辑
    }

    // --- 状态保存与恢复的核心实现 ---
    @Override
    protected Parcelable onSaveInstanceState() {
        // 先获取父类的状态,必须保留这个操作,否则会丢失View的基础状态
        Parcelable superState = super.onSaveInstanceState();
        // 创建我们自定义的SavedState对象,传入父类状态
        SavedState savedState = new SavedState(superState);
        // 把自定义状态变量赋值给SavedState
        savedState.stampText = this.stampText;
        savedState.stampTimeStamp = this.stampTimeStamp;
        savedState.stampIconId = this.stampIconId;
        savedState.stamped = this.stamped;
        return savedState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        // 先判断传入的状态是不是我们自定义的SavedState
        if (!(state instanceof SavedState)) {
            // 如果不是,直接交给父类处理
            super.onRestoreInstanceState(state);
            return;
        }
        // 转换为我们的SavedState,先恢复父类状态
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        // 恢复自定义状态变量
        this.stampText = savedState.stampText;
        this.stampTimeStamp = savedState.stampTimeStamp;
        this.stampIconId = savedState.stampIconId;
        this.stamped = savedState.stamped;
        // 恢复状态后记得刷新View
        invalidate();
    }

    // 静态内部类,用来存储自定义状态,必须继承BaseSavedState
    static class SavedState extends BaseSavedState {
        String stampText;
        String stampTimeStamp;
        int stampIconId;
        boolean stamped;

        SavedState(Parcelable superState) {
            super(superState);
        }

        // 从Parcel中读取状态的构造方法
        private SavedState(Parcel in) {
            super(in);
            // 按写入顺序读取变量
            stampText = in.readString();
            stampTimeStamp = in.readString();
            stampIconId = in.readInt();
            stamped = in.readByte() != 0; // boolean用byte存储
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            // 把自定义变量写入Parcel
            out.writeString(stampText);
            out.writeString(stampTimeStamp);
            out.writeInt(stampIconId);
            out.writeByte((byte) (stamped ? 1 : 0));
        }

        // 必须实现的CREATOR,用于创建SavedState实例
        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
            @Override
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
}
关键注意事项
  • 必须设置View的ID:在布局文件中给StampView添加android:id="@+id/xxx",系统只会为有ID的View保存状态。
  • 不要忽略父类状态:onSaveInstanceState()中必须先获取super.onSaveInstanceState(),onRestoreInstanceState()中也要先恢复父类状态,否则会丢失View的基础状态(比如可见性、位置等)。
  • Parcelable的读写顺序要一致:writeToParcel()和SavedState(Parcel in)中的变量读写顺序必须完全相同,否则会出现状态错乱。
  • 恢复状态后刷新View:在onRestoreInstanceState()最后调用invalidate(),确保View根据恢复的状态重新绘制。

这样修改后,你的StampView就能正确保存和恢复状态啦!

内容的提问来源于stack exchange,提问作者szaske

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:05:35