在用Fragment做Tab页面,发现有时候进入应用会同时显示多个Tab内容,UI发生重叠。

当应用被强行关闭后(通过手机管家软件手动强关,或系统为节省内存自动关闭应用),再次进入应用时,每次都有这现象。

第一次进入应用时,根据选择的tab分别创建对应的Fragment,之后每次选择页面时隐藏其他tab内容。

通过分析发现,正常back键退出应用时,Activity及Fragment对象会被销毁,因此再次进入时会在切换到Tab时创建对应的Fragment对象。

但是当强行关闭应用后,Activity虽然被回收,但Fragment对象仍然保持,再次进入应用时,系统会分别调用Fragment的onAttach方法将其附加到Activity上,

02-08 12:41:24.107: D/FragmentTab1(7032): onAttach

02-08 12:41:24.107: D/FragmentTab3(7032): onAttach

这里对应的就是强行关闭应用前的fragment对象,

后面会分别调用两个fragment的onCreateView方法,因此这两个Fragment对应的View层次结构都会加到Activity的View层次中。

虽然setSelection方法会把所有fragment先隐藏再显示选中的对象,但由于此时Activity中Fragment对象的成员变量还未初始化,因此会再次实例化fragment对象,

之后add、show及hide的都是在第二次创建的对象上操作的,而之前被保持的fragment对象的视图层次已经反映到Activity视图中并且不会被hide,因此发生了上述重叠现象。

 

解决方法:

在Activity的onAttachFragment方法中,有一个fragment参数,它就是onAttach方法对应的Fragment对象,

通过判断这个fragment对象,如果属于我们的FragmentTabX类并且该类还未被实例化过,则将Activity的成员变量mFragmentTabX指向该fragment对象,这样就可以在原来的fragment对象上操作add/show/hide,因此不会有重叠现象。

@Override  
    public void onAttachFragment(Fragment fragment) {  
        // TODO Auto-generated method stub  
        super.onAttachFragment(fragment);  
        Log.d(TAG,"onAttachFragment");  
          //mTab1,mTab2,mTab3 是在Activity中创建的Fragment
        if (mTab1 == null && fragment instanceof FragmentTab1) {  
            mTab1 = (FragmentTab1)fragment;  
        }else if (mTab2 == null && fragment instanceof FragmentTab2) {  
            mTab2 = (FragmentTab2)fragment;  
        }else if (mTab3 == null && fragment instanceof FragmentTab3) {  
            mTab3 = (FragmentTab3)fragment;  
        }  
    }

 

 

-------------------------------------华丽的分割线------------------------------------------

以下参考:

上面的貌似说的很有道理,但是测试了一下还是不行,也许是我遇到的问题跟他说的不一致。

我遇到的问题是:当报错时(比如空指针)主页面出现Fragment重叠。

在debug的时候,发现CarFragment是执行了onCreateView()的,意味着成功生成了车辆管理的界面,但究竟为什么仍然显示的是SupplyFragment的界面呢,直观感觉,SupplyFragment像一层蒙板一样放在最上层,点击其他4个tab栏,生成的Fragment都被隐藏在了它的下面。

后来在google查到相关资料,原因是:当Fragment长久不使用,系统进行回收,FragmentActivity调用onSaveInstanceState保存Fragment对象。很长时间后,再次打开app,系统恢复保存的Fragment,但是在FragmentActivity重新执行生命周期的时候,我们重新生成了fragment对象附加到该FragmentActivity,系统恢复的fragment和FragmentActivity失去关联,进而出错。

解决方案为以下两种:

方法1:在fragmentActivity里oncreate方法判断savedInstanceState==null才生成新Fragment,否则不做处理。

方法2:在fragmentActivity里重写onSaveInstanceState方法,但不做实现,也就是将super.onSaveInstanceState(outState)注释掉。

方法2很好理解,当系统要回收Fragment时,我们告诉系统:不要再保存Fragment。相当于用户回到app的时候,我们就当用户是第一次打开app(因为很长时间没有操作了)。

方法1理论上没有问题,但在测试的时候,用了一种非常规的方案,横竖屏切换来测试,而在横竖屏切换时,系统会首先销毁FragmentActivity再重新生成,无法模拟测试条件,还要再研究。

方法1博主亲测,没有什么卵用。