Android中手动调用onSaveInstanceState无效的问题排查
首先得明确一个核心点:你手动调用onSaveInstanceState(b)的方式根本不会让Android框架保存这个Bundle。
onSaveInstanceState这个方法的设计是让Android框架在特定生命周期节点(比如Activity/Fragment即将被系统回收、配置发生变化时)主动调用的,框架会自己创建一个Bundle实例传进来,然后把这个Bundle存入自己的状态管理体系中,这样在后续重建时才能把它回传给onCreate/onViewCreated。
而你在onDestroy里自己new了一个Bundle,调用onSaveInstanceState(b)只是让Fragment把数据写入这个你自己创建的Bundle里,但这个Bundle并没有被交给框架保存——框架完全不知道这个Bundle的存在,所以当你重新打开Fragment时,自然拿不到这个数据。
另外补充个细节:当用户点击返回按钮时,这属于用户主动销毁Fragment/Activity,Android框架本来就不会触发onSaveInstanceState的调用(这个方法是为了应对系统主动回收的场景,不是用户主动销毁),所以你想通过这种方式保存状态从根源上就不符合框架的设计逻辑。
正确的状态保存方式
1. 使用ViewModel(推荐)
ViewModel是Android Jetpack提供的专门用于保存UI状态的组件,它的生命周期不受Fragment/Activity的销毁重建影响,非常适合这种场景:
// 定义ViewModel类 public class MyViewModel extends ViewModel { private MyModel myModel; public MyModel getMyModel() { return myModel; } public void setMyModel(MyModel myModel) { this.myModel = myModel; } } // 在你的Fragment中 private MyViewModel viewModel; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); viewModel = new ViewModelProvider(this).get(MyViewModel.class); // 从ViewModel恢复数据 MyModel savedModel = viewModel.getMyModel(); if (savedModel != null) { // 恢复UI状态 } } @Override public void onDestroy() { super.onDestroy(); // 把数据存入ViewModel viewModel.setMyModel(myModel); }
2. 利用Fragment的setRetainInstance(true)(旧方案,不推荐)
这个方法可以让Fragment在Activity重建时保留实例,但它不适合处理用户主动销毁的场景(比如返回键),不过如果你的场景只是配置变化的话可以用:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); // 保留Fragment实例 }
3. 如果你非要用Bundle保存(仅适用于框架触发的重建)
如果你的需求是在系统回收时保存状态,那应该在框架正常调用onSaveInstanceState时写入数据,而不是手动调用:
@Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable("mymodel", myModel); // 框架会自动保存这个outState } // 然后在onCreate或onViewCreated中恢复 @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (savedInstanceState != null) { myModel = savedInstanceState.getParcelable("mymodel"); } }
但要注意:用户点击返回按钮时,框架不会调用onSaveInstanceState,所以这种方式还是无法保存这种场景下的状态,这时候ViewModel是最优解。
内容的提问来源于stack exchange,提问作者j2emanue

