Activity + Fragment + ViewPager Activity被销毁

  • Post author:
  • Post category:其他




问题:

  • Activity重建后,为什么 ViewPager里的Fragment多了一倍

    • 我的case:自己在ViewPager的adapter里 new的Fragment,系统又 restore 一个 Fragment。
    • 然后业务逻辑用 new的Fragment,系统却用restore的Fragment,导致new的Fragment声明周期都没走,之后就会各种异常。
  • 怎样复现 activity 被回收: 开发者选项,点击 不保存活动

    • 这样Activity stack中不可见的(即不在stack 顶部的Activity都会被回收 (走onActivityDestroyed回调))
  • 什么时候,FragmentManager的内容被 restore: Activity的 super.onCreate(savedInstanceState); 执行完后恢复

    • debug查看
  • 怎么创建Fragment (下文有写)



结论先行

  • 创建Fragment时,要考虑到Fragment被恢复的case,这时不该 new,而是 恢复状态
  • Activity被 销毁 重建后,如果用ViewPager用的 FragmentStatePagerAdapter,系统会重新创建 Fragment 实例

    • Activity被销毁时,FragmentManagetImpl 调用saveAllState,将保存Fragment的状态 FragmentManagerState(Parcelable子类 IPC跨进程使用)。
    • Activity重建时,会根据 FragmentManagerState ,重新创建Fragment
  • 编写Activity时,一定要考虑他会被destroy的情景(比如内存紧张, 这不受你控制)

    • 一个内存泄漏就可以引发,当然泄漏多了就OOM,看起来指标不治本
Parcelable saveAllState() {
	                FragmentManagerState fms = new FragmentManagerState();
                fms.mActive = active;
                fms.mAdded = added;
                fms.mBackStack = backStack;



怎么创建Fragment

创建时,一定要判断 FragmentMananger 中是否已有Fragment



Fragment的创建、恢复(不用ViewPager)
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);
    }
}


Fragment + ViewPager

YourActivity

    private final YourFragmentAdapter adapter = new YourFragmentAdapter(getSupportFragmentManager());

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
    	adapter.initData();
    	viewPager.setAdapter(adapter);
    }
    //...........

YourAdapter

public class YourAdapter extends FragmentStatePagerAdapter {

    private final List<Fragment> tabFragments = new ArrayList<>();

    public YourAdapter(FragmentManager supportFragmentManager) {
        super(supportFragmentManager);
    }

    private void initData(FragmentManager fragmentManager) {
        YouFragment1 normalFragment = null;
        YouFragment2 specialFragment = null;

        if (fragmentManager != null && fragmentManager.getFragments().size() > 0) {
            List<Fragment> fragments =  fragmentManager.getFragments();
            for (int i = 0; i<fragments.size(); i++) {
                Fragment fragment = fragments.get(i);
                if (fragment instanceof YouFragment1) {
                    normalFragment = (YouFragment1) fragment;
                } else if (fragment instanceof YouFragment2) {
                    specialFragment = (YouFragment2) fragment;
                }
            }
        }

        if (normalFragment == null) {
            normalFragment = YouFragment1.newInstance();
        }
        if (specialFragment == null) {
            specialFragment = YouFragment2.newInstance();
        }

        tabFragments.add(normalFragment);
        tabFragments.add(specialFragment);
    }

    @Override
    public Fragment getItem(int position) {
        return tabFragments.get(position);
    }

    @Override
    public int getCount() {
        return tabFragments.size();
    }



FragmentPagerAdapter 与 FragmentStatePagerAdapter

  • 看这个

    文章
  • FragmentPagerAdapter 是将Fragment保存到 FragmentManager里,进行复用

    • 适合静态的、少界面的ViewPager,加载Fragment过多,会增加内存消耗
  • FragmentStatePagerAdapter 是通过对 FragmentManagerState 来实现状态的复用(Fragment会被新创建,但状态一致)

    • 默认不保存所有的Fragment,而是 前页面1个+当前+后页面1个= 3个页面被缓存
    • 前面、后面页面缓存个数通过 ViewPager setOffscreenPageLimit (int limit)设置
    • 可以在Activity销毁重建后,回复UI状态



版权声明:本文为zhjali123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。