自定义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
相关产品推荐
相关产品推荐

