Frament 重叠 解决方案

1、Fragment重叠的原因

        1.support库24.0.0之前有一个bug,就是在FragmentManager保存Fragment实例状态的时候,没有保存mHidden, 因此重创建之后Fragment都处于显示状态就造成了重叠

      2.虽然我在24.0.0之后在activity内存重启重新创建的时候FragmentManager帮我们保存了mHidden属性,但是如果我们在初始化Fragment也同样会出现重叠现象。

    private void initFragment() {
        fragmentOne = new FragmentOne();
        fragmentTwo = new FragmentTwo();
        fragmentThree = new FragmentThree();
        fragmentList.add(fragmentOne);
        fragmentList.add(fragmentTwo);
        fragmentList.add(fragmentThree);
    }

   我们知道当activity当内存不足销毁重建的时候FragmentManager帮我们保存一些属性并且重新创建fragment实例,由于每次activity重建onCreate方法中我们又实例化了fragment(由于fragment默认是透明的,FragmetMangeager恢复重建的fragment实例与onCreate新创建的实例重叠,隐藏状态不同)导致fragment重叠现象。

2、解决方案

   首先对于出现内存重启Activity销毁现象我们不好调试,我们可以在设置开发者选项中把 不保留活动 勾上,这样我们每次按home键在重新返回就能模拟重建环境。

   我们先贴一下我们平常出问题的代码

public class MethodTwoActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {
    private RadioGroup mMainTabGroup;
    private FragmentOne fragmentOne;
    private FragmentTwo fragmentTwo;
    private FragmentThree fragmentThree;
    private List fragmentList = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_public);
        setTitle("方法二");
        mMainTabGroup = (RadioGroup) findViewById(R.id.main_tab_group);
        mMainTabGroup.setOnCheckedChangeListener(this);
        initFragment();
        ((RadioButton) mMainTabGroup.getChildAt(0)).setChecked(true);

    }

    private void initFragment() {
        fragmentOne = new FragmentOne();
        fragmentTwo = new FragmentTwo();
        fragmentThree = new FragmentThree();
        fragmentList.add(fragmentOne);
        fragmentList.add(fragmentTwo);
        fragmentList.add(fragmentThree);
    }

    /**
     * 既然恢复的时候走两遍我们就控制一下
     */
    private int mCurrentCheckedId;

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        if (mCurrentCheckedId != checkedId)
            mCurrentCheckedId = checkedId;
        else {
            return;
        }
        switch (checkedId) {
            case R.id.rb_one:
                addContentLayout(fragmentOne);
                break;
            case R.id.rb_two:
                addContentLayout(fragmentTwo);
                break;
            case R.id.rb_three:
                addContentLayout(fragmentThree);
                break;
            default:
                break;
        }
    }


    private void addContentLayout(Fragment fragment) {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        for (Fragment f : fragmentList) {
            if (f != fragment&&f.isAdded()) {
                ft.hide(f);
            }
        }
        if (fragment.isAdded()) {
            if (fragment.isHidden()) {
                ft.show(fragment);
            }
        } else {
            ft.add(R.id.main_content, fragment, fragment.getClass().getSimpleName());
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        }

        ft.commit();
    }

一、方法一

  重写activity的onSaveInstanceState方法 并注释掉super方法。

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

 注释掉此父类方法,activity在销毁的时候不会保存视图等相关数据,当然也不保存fragment的状态数据。

   二、方法二

  重写activity的onSaveInstanceState方法 并在方法中通过FragmentTransaction移除我们的fragment

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.remove(fragmentOne);
        transaction.remove(fragmentTwo);
        transaction.remove(fragmentThree);
        transaction.commitAllowingStateLoss();
        //这个方法会帮我们保留选中位置状态
        super.onSaveInstanceState(outState);
    }

 缺点: 和方法一都是沒有保存Fragment的相关数据,但是我们执行了activity 的 super.onSaveInstanceState(outState);方法,经过debug调试activity会帮我保留选中的位置(恢复的时候底部按钮选中状态可判断)

 在我们按home键重新回到activity执行onCreate 通过调试发现 onCheckedChanged方法会走三次,前两次是默认选中((RadioButton) mMainTabGroup.getChildAt(0)).setChecked(true)导致(我们可以通过mCurrentCheckedId变量控制下面逻辑是否走)第三次就是执行activity帮我保留选中的位置onCheckedChanged。

​​    /**
     * 既然恢复的时候走两遍我们就控制一下
     */
    private int mCurrentCheckedId;

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        if (mCurrentCheckedId != checkedId)
            mCurrentCheckedId = checkedId;
        else {
            return;
        }
        switch (checkedId) {
            case R.id.rb_one:
                addContentLayout(fragmentOne);
                break;
            case R.id.rb_two:
                addContentLayout(fragmentTwo);
                break;
            case R.id.rb_three:
                addContentLayout(fragmentThree);
                break;
            default:
                break;
        }
    }

      三、方法三

  直接上代码

public class MethodThreeActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {
    private RadioGroup mMainTabGroup;
    private FragmentOne fragmentOne;
    private FragmentTwo fragmentTwo;
    private FragmentThree fragmentThree;
    private List fragmentList = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_public);
        setTitle("方法三");
        mMainTabGroup = (RadioGroup) findViewById(R.id.main_tab_group);
        mMainTabGroup.setOnCheckedChangeListener(this);
        if (savedInstanceState != null) {
            fragmentOne = (FragmentOne) getSupportFragmentManager().findFragmentByTag(FragmentOne.class.getSimpleName());
            fragmentTwo = (FragmentTwo) getSupportFragmentManager().findFragmentByTag(FragmentTwo.class.getSimpleName());
            fragmentThree = (FragmentThree) getSupportFragmentManager().findFragmentByTag(FragmentThree.class.getSimpleName());
            //这块一定要 这样写如果我们进入界面只添加了fragmentOne 那就会引起空指针异常
            if (fragmentOne != null) {
                fragmentList.add(fragmentOne);
            } else {
                fragmentOne = new FragmentOne();
                fragmentList.add(fragmentOne);
            }
            if (fragmentTwo != null) {
                fragmentList.add(fragmentTwo);
            } else {
                fragmentTwo = new FragmentTwo();
                fragmentList.add(fragmentTwo);
            }
            if (fragmentThree != null) {
                fragmentList.add(fragmentThree);
            } else {
                fragmentThree = new FragmentThree();
                fragmentList.add(fragmentThree);
            }
        } else {
            initFragment();
        }
        ((RadioButton) mMainTabGroup.getChildAt(0)).setChecked(true);

    }

    private void initFragment() {
        fragmentOne = new FragmentOne();
        fragmentTwo = new FragmentTwo();
        fragmentThree = new FragmentThree();
        fragmentList.add(fragmentOne);
        fragmentList.add(fragmentTwo);
        fragmentList.add(fragmentThree);
    }

    /**
     * 既然恢复的时候走两遍我们就控制一下
     */
    private int mCurrentCheckedId;

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        if (mCurrentCheckedId != checkedId)
            mCurrentCheckedId = checkedId;
        else {
            return;
        }
        switch (checkedId) {
            case R.id.rb_one:
                addContentLayout(fragmentOne);
                break;
            case R.id.rb_two:
                addContentLayout(fragmentTwo);
                break;
            case R.id.rb_three:
                addContentLayout(fragmentThree);
                break;
            default:
                break;
        }
    }

    private void addContentLayout(Fragment fragment) {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        for (Fragment f : fragmentList) {
            if (f != fragment && f.isAdded()) {
                ft.hide(f);
            }
        }
        if (fragment.isAdded()) {
            if (fragment.isHidden()) {
                ft.show(fragment);
            }
        } else {
            ft.add(R.id.main_content, fragment, fragment.getClass().getSimpleName());
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        }
        ft.commit();
    }
}

   在activity重建的时候如果savedInstanceState != null来判断是否activity重建,通过findFragmentByTag方法找到FragmentManager帮我们恢复重建Fragment(保存了退到后台销毁的Fragment相关视图属性)。这样我们不仅不会多创建没用的实例也保存了fragment视图相关状态信息。

Demo下载

https://github.com/lurenman/FragmentOverlapDemo

 

 

你可能感兴趣的:(android,fragment重叠,fragment)