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状态

Hello World

I’ve thought about it many times to create a website for myself. Finally, this came true. I wish I can create more things, have more influence and take more actions.

Of course, we hear Bruce Lee say, “Like everyone else, you want to learn the way to win, but never to accept the way to lose, to accept defeat, to learn to die is to be liberated from it. So when tomorrow comes, you must free your ambitious mind, and learn the art of dying.” Maybe after 10 years, I will accept the philosophy. But not today.