Activity + Fragment + ViewPager Activity被销毁

问题:

  • Activity重建后,为什么 ViewPager里的Fragment多了一倍
    • 我的case:自己在ViewPager的adapter里 new的Fragment,系统又 restore 一个 Fragment。
    • 然后业务逻辑用 new的Fragment,系统却用restore的Fragment,导致new的Fragment声明周期都没走,之后就会各种异常。

结论先行

  • 创建Fragment时,要考虑到Fragment被恢复的case,这时不该 new,而是 恢复状态
  • Activity被 销毁 重建后,如果用ViewPager用的 FragmentStatePagerAdapter,系统会重新创建 Fragment 实例
    • Activity被销毁时,FragmentManagetImpl 调用saveAllState,将保存Fragment的状态 FragmentManagerState(Parcelable子类 IPC跨进程使用)。
    • Activity重建时,会根据 FragmentManagerState ,重新创建Fragment
  • 编写Activity时,一定要考虑他会被destroy的情景(比如内存紧张, 这不受你控制)
    • 一个内存泄漏就可以引发,当然泄漏多了就OOM,看起来指标不治本
  • 怎样模拟Activity被销毁?可以去开发者设置里,勾选 不保存活动 (我没试过,之后试过再确认)
Parcelable saveAllState() {
                    FragmentManagerState fms = new FragmentManagerState();
                fms.mActive = active;
                fms.mAdded = added;
                fms.mBackStack = backStack;

怎么创建Fragment

在创建前先判断FragmentManager中是否已该Activity

        adapter = new FragmentStatePagerAdapter(getChildFragmentManager());
        if (getFragmentManager().getFragments() != null) {
            adapter.initData(getFragmentManager().getFragments());
        } else {
            adapter.initData();
        }

如果不用ViewPager。Fragment的创建、恢复

private MainFragment mainFragment;
private SecondaryFragment secondaryFragment;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        mainFragment = (MainFragment) fm.getFragment(savedInstanceState, MainFragment.TAG);
        secondaryFragment = (SecondaryFragment) fm.getFragment(savedInstanceState, SecondaryFragment.TAG);
    }
    if (mainFragment == null) {
        mainFragment = new MainFragment();
    }
    if(secondaryFragment == null){
        secondaryFragment = new SecondaryFragment()
    }
    // ViewPager 的相关操作
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if (mainFragment.isAdded()) {
        fm.putFragment(outState, MainFragment.TAG, mainFragment);
    }
    if (secondaryFragment.isAdded()) {
        fm.putFragment(outState, SecondaryFragment.TAG, secondaryFragment);
    }
}

FragmentPagerAdapter 与 FragmentStatePagerAdapter

  • 看这个文章
  • FragmentPagerAdapter 是将Fragment保存到 FragmentManager里,进行复用
    • 适合静态的、少界面的ViewPager,加载Fragment过多,会增加内存消耗
  • FragmentStatePagerAdapter 是通过对 FragmentManagerState 来实现状态的复用(Fragment会被新创建,但状态一致)
    • 默认不保存所有的Fragment,而是 前页面1个+当前+后页面1个= 3个页面被缓存
    • 前面、后面页面缓存个数通过 ViewPager setOffscreenPageLimit (int limit)设置
    • 可以在Activity销毁重建后,回复UI状态

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注