Fragment中使用ViewPager+Fragment模式,不保留后台活动,Activity被销毁重建后,Fragment异常

原因分析

Activity添加Fragment后,Activity会保存所有被添加的Fragment的状态;由于系统内存等问题Activity被回收后,Activity会自己重新创建原来保存的这些Fragment并attach;但我们如果使用引用方式保存并使用ViewPager里的Fragment,会造成异常;

问题解决

方案1

Activity不要调用父类保存Fragment状态的方法;

@Override
protected void onSaveInstanceState(Bundle outState) {
 //   super.onSaveInstanceState(outState);
}

方案2

在Fragment的onCreate方法开始调用下面方法,清除当前Fragment所属的所有子Fragment;

private void clearFragments(){
        FragmentManager fm = getChildFragmentManager();
        if(fm != null && fm.getFragments() != null && fm.getFragments().size() > 0){
            FragmentTransaction ft = fm.beginTransaction();
            for(Fragment fragment : fm.getFragments()){
                ft.remove(fragment);
            }
            ft.commit();
        }
}

方案3

覆写Activity的onCreate方法:

@Override
protected void onCreate(Bundle savedInstanceState) {
        if(savedInstanceState != null){
            savedInstanceState.remove("android:support:fragments");
        }

        super.onCreate(savedInstanceState);

        ...
}

方案4

获取ViewPager里的Fragment时,不要通过引用方式获取,改为如下方式获取:   

 /**
     * ViewPager根据position找指定位置的Fragment
     * @param fragmentManager
     * @param viewPagerId
     * @param fragmentPagerAdapter
     * @param position
     * @return
     */
    public static Fragment getFragment(FragmentManager fragmentManager, int viewPagerId, FragmentPagerAdapter fragmentPagerAdapter, int position){
        if(fragmentManager != null){
            String tag;
            if(fragmentPagerAdapter != null){
                tag = "android:switcher:" + viewPagerId + ":" + fragmentPagerAdapter.getItemId(position);
            } else {
                tag = "android:switcher:" + viewPagerId + ":" + position;
            }

            return fragmentManager.findFragmentByTag(tag);
        } else {
            return null;
        }
    }

结论

上面四种方式,均可解决Activity自己重建Fragment造成的一些问题;但方案1、方案2、方案3可维护性及可扩展性不好,推荐使用方案4;

问题思考

1. 方案2中,Activity销毁被重建时,子Fragment会被自动重建,但在onCreate用代码清除后,后面会由我们的业务代码再重新创建;

2. 方案1、方案2、方案3其实都是在想办法清除掉原有的Fragment及其状态,方案4只是修改了获取Fragment的方式,较好地保留了原有Fragment状态逻辑;

猜你喜欢

转载自blog.csdn.net/enjoyinwind/article/details/83755195