一、临时状态保存(配置变更场景)
1. onSaveInstanceState机制
-
触发时机:
-
配置变更(屏幕旋转、语言切换等)
-
内存不足时后台Activity被回收
-
不会在正常finish()时调用
-
-
典型使用:
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("KEY_USER_INPUT", editText.getText().toString()); outState.putInt("KEY_SCROLL_POSITION", recyclerView.getScrollY()); }
2. 数据恢复流程
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
String userInput = savedInstanceState.getString("KEY_USER_INPUT");
int scrollPos = savedInstanceState.getInt("KEY_SCROLL_POSITION");
// 恢复UI状态...
}
}
二、持久化状态保存
1. ViewModel保存
-
优势:
-
survives配置变更
-
不依赖Bundle大小限制
public class MyViewModel extends ViewModel { private MutableLiveData<String> userInput = new MutableLiveData<>(); public LiveData<String> getUserInput() { return userInput; } } // Activity中使用 viewModel.getUserInput().observe(this, input -> { editText.setText(input); });
-
2. 本地存储方案
存储方式 | 适用场景 | 示例 |
---|---|---|
SharedPreferences | 简单键值对 | 用户偏好设置 |
Room数据库 | 结构化数据 | 表单草稿保存 |
文件存储 | 复杂对象/大数据 | 图片缓存 |
三、自动状态保存的UI组件
1. 原生支持保存的View
-
EditText(文本内容/光标位置)
-
CheckBox/RadioButton(选中状态)
-
RecyclerView(滚动位置)
2. 自定义View实现
public class CustomView extends View {
// 必须的ID设置
public CustomView(Context context) {
super(context);
setId(View.generateViewId());
}
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable("superState", super.onSaveInstanceState());
bundle.putInt("CUSTOM_STATE", customValue);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
super.onRestoreInstanceState(bundle.getParcelable("superState"));
customValue = bundle.getInt("CUSTOM_STATE");
}
}
四、状态保存最佳实践
-
分层保存策略:
-
瞬时UI状态 →
onSaveInstanceState()
-
短期数据 →
ViewModel
-
长期数据 → 持久化存储
-
-
Bundle使用注意:
-
避免保存大对象(>1MB可能被系统丢弃)
-
优先保存最小必要数据(如ID而非完整对象)
-
-
多Fragment场景:
// Fragment中设置 setRetainInstance(true); // 保留非UI相关数据
五、常见问题解决方案
1. 状态未正确恢复
-
检查点:
-
是否调用了super方法
-
View是否设置了android:id
-
是否在setContentView之后恢复
-
2. 数据序列化问题
-
复杂对象处理:
// 实现Parcelable public class User implements Parcelable { private String name; protected User(Parcel in) { name = in.readString(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); } public static final Creator<User> CREATOR = new Creator<User>() { @Override public User createFromParcel(Parcel in) { return new User(in); } }; }
3. 异步加载冲突
// 使用isChangingConfigurations判断
if (!isChangingConfigurations()) {
// 只有真正销毁时才释放资源
releaseHeavyResource();
}
六、进阶回答技巧
-
系统原理层面:
Activity状态保存实际是通过ActivityThread维护的ActivityClientRecord实现的,当系统触发保存时,会通过Instrumentation.callActivityOnSaveInstanceState()回调到我们的Activity -
架构设计层面:
在APP中,采用三级状态保存:-
购物车商品ID通过ViewModel保存
-
搜索框文本通过onSaveInstanceState保存
-
用户偏好通过SharedPreferences持久化
-
-
性能优化层面:
通过以下措施优化状态保存:-
延迟加载非关键视图(ViewStub)
-
分页加载列表数据
-
使用SavedStateRegistry替代部分Bundle操作
-