Android:Activity中Fragment的状态保存与恢复需求
解决方案:恢复到上次显示的Fragment状态
咱们先梳理下现有代码里影响状态恢复的几个问题:
onCreate里不管有没有保存的状态,都直接初始化intro1,导致每次重启Activity都会回到第一个Fragment;- 静态变量
fragment、fragmentManager、fragmentTransaction容易引发内存泄漏,还没法准确跟踪当前显示的Fragment; onSaveInstanceState里保存的fragment不一定是当前正在显示的实例,恢复时容易出错。
下面是修改后的完整代码和关键改动说明:
1. 重构IntroductionActivity代码
public class IntroductionActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "IntroductionActivity"; // 用成员变量跟踪当前Fragment,替换原来的静态变量 private Fragment currentFragment; private static final String KEY_CURRENT_FRAG_TAG = "current_fragment_tag"; private String currentFragmentTag; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_introduction); ActionBar actionbar = getSupportActionBar(); if (savedInstanceState != null) { // 从保存的状态中读取上次的Fragment标签 currentFragmentTag = savedInstanceState.getString(KEY_CURRENT_FRAG_TAG); // 通过标签获取已保存的Fragment实例 currentFragment = getSupportFragmentManager().findFragmentByTag(currentFragmentTag); } // 没有保存状态时,默认加载第一个Fragment if (currentFragment == null) { currentFragment = new Intro1(); currentFragmentTag = "intro1"; getSupportFragmentManager().beginTransaction() .add(R.id.fragment_container, currentFragment, currentFragmentTag) .commit(); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // 保存当前Fragment的标签,比直接存Fragment实例更稳定 outState.putString(KEY_CURRENT_FRAG_TAG, currentFragmentTag); } @Override public void onClick(View v) { // 按需添加其他点击逻辑 } // 改成非静态方法,避免静态引用带来的问题 public void switchToIntro2() { currentFragment = new Intro2(); currentFragmentTag = "intro2"; getSupportFragmentManager().beginTransaction() .replace(R.id.fragment_container, currentFragment, currentFragmentTag) .commit(); } }
2. 修改Intro1 Fragment代码
把原来调用静态方法的逻辑改成通过Activity实例调用:
public class Intro1 extends Fragment{ private View rootView; private Button intro1nxtButton; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { rootView = inflater.inflate(R.layout.fragment_intro_1, container, false); intro1nxtButton = rootView.findViewById(R.id.intro1Next_button); intro1nxtButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 强转为宿主Activity,调用切换Fragment的方法 ((IntroductionActivity) getActivity()).switchToIntro2(); } }); return rootView; } }
3. 关键改动说明
- 移除静态变量:静态引用会长期持有Activity实例,容易引发内存泄漏,改用成员变量+Fragment标签的方式跟踪状态;
- 正确恢复状态:启动Activity时先检查
savedInstanceState,如果存在就恢复上次显示的Fragment,不存在才加载默认的Intro1; - 保存Fragment标签:在
onSaveInstanceState中保存当前Fragment的标签,比直接序列化Fragment实例更稳定,避免序列化异常; - 非静态方法切换Fragment:把原来的静态
doStuff改成Activity的成员方法,通过Fragment获取宿主Activity实例调用,更符合Android组件生命周期规范。
这样修改后,不管是按下返回键关闭Activity,还是因配置变更重启Activity,再次打开时都会自动恢复到上次显示的Fragment(比如Intro2),而不是回到初始的Intro1。
内容的提问来源于stack exchange,提问作者Aditya Marathe
相关产品推荐
相关产品推荐

