天天看点

Activity中Fragment重叠问题

Activity中Fragment重叠问题

  图1                       

Activity中Fragment重叠问题

  图2

先简单说一下我碰到的问题,图1是我的主界面,采用底部导航+FrameLayout来实现Fragment的切换,当app在某一个界面崩溃后,回到了主界面,就出现了Fragment重叠问题,如图2。  因为我之前还有一个项目也是采用的底部导航+FrameLayout,但当初我在开发的时候并没有碰到这种bug,所以打开之前开发的那个app捣鼓了一会,也成功出现了这个bug,当然不是崩溃引起的,而是通过横竖屏切换。

       仔细想了一下,无论页面崩溃还是横竖屏切换,都要重走activity的生命周期,就相当于重新打开了这个界面,按道理一切都应该重新开始才对,为什么里面的Fragment没有被销毁。带着疑问我默默打开浏览器百度了一下。看了几篇博客之后,知道了问题所在。这两篇博客比较靠谱点  https://blog.csdn.net/u011734444/article/details/53347265   

                                                    https://blog.csdn.net/yuzhiqiang_1993/article/details/75014591

       原因:当我们旋转屏幕的时候,activity会被销毁并重新创建,并且在销毁之前执行了onSaveInstanceState(Bundle outState)这个方法。这个方法会保存activity的一些信息,其中就包括添加过的fragment,当activity被重新创建时,会初始化其中的变量,这个时候点击底部导航的话会重新去添加fragment,也就导致了重叠的问题。

       既然Fragment没有被销毁并且被保存在了bundle中,那我们就可以把它们取出来进行复用,并且需要知道从bundle中取出来的是哪个Fragment,所以我们在添加Fragment的时候需要设置Tag,这样就知道取出来的是哪个Fragment了。

ft.add(R.id.main_framlayout, fragment, tag);//第三个参数就是tag      

首先是添加Fragment

private FragmentManager fm = getSupportFragmentManager();
private FragmentTransaction ft;
//Fragment集合
private Fragment[] fragments = new Fragment[]{new HomeFragment(), new ReportFragment(), new MineFragment()};

private Fragment mCurrentShowFrag;//当前展示的fragment
private int currentFragPosition = 0;//记录当前展示fragment的position 默认第一个为0

//判断当前要显示fragment是否被添加,没有则添加,已添加直接show()
private void showFragment(int position) {
        ft = fm.beginTransaction();//不可作为全局变量,每次切换Fragment的时候,都必须开启一个新事务
        Fragment fragment = fragments[position];

        if (mCurrentShowFrag != null) {
            ft.hide(mCurrentShowFrag);
        }
        
        if (!fragment.isAdded()) {
            Logger.i("", "------------noadd");
            ft.add(R.id.main_framlayout, fragment, "" + position);//第三个参数就是fragment所对应的tag
        } else {
            Logger.i("", "------------added");
            ft.show(fragment);
        }
        mCurrentShowFrag = fragment;
        ft.commit();
}
           

       当页面崩溃或横竖屏切换引起界activity重新加载 ,之前的Fragment并没有被销毁,只是保存到了savedInstanceState,当重走onCeate方法时,在savedInstanceState根据tag取到对应的fragment

private void initFragmentList(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            currentFragPosition = savedInstanceState.getInt("position");//恢复崩溃之前framgent所对应的position
            mCurrentShowFrag = fragments[currentFragPosition];//恢复底部导航栏的正确选中位置
            bottom_bar.setFirstSelectedPosition(currentFragPosition).initialise();
            for (int i = 0; i < fragments.length; i++) {
                //这里需要判断fragment之前有没有被添加,如果没有添加,则通过tag是取不到fragment的,为null
                if (fm.findFragmentByTag("" + i) != null) {
                    fragments[i] = fm.findFragmentByTag("" + i);
                }
            }
        }
}
           

到这里就不会出现fragment的重叠问题了,当然还有一个小问题需要处理一下,如果我崩溃之前位于第三个Fragment,但是重新加载后显示的是第一个Fragment,并且底部导航也是第一个被选中,所以需要记录一下当前显示fragment的索引currentFragPosition ,并且在崩溃重走onSavedInstance()方法的时候进行保存,然后在onCreate()中重新赋值,通过currentFragPosition来决定显示哪个Fragment,底部导航栏哪一个被选中

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initFragmentList(savedInstanceState);
        showFragment(currentFragPosition);
}   


 @Override
protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("position", currentFragPosition);
}
           

  多一点记录,多一点收获,多一份感悟。ヾ(◍°∇°◍)ノ゙加油!

继续阅读