前言:最近项目中用BottomNavigationView动态添加几个Fragment于FrameLayout中,bug就在我切换其他APP操作一会后,再回到当前APP,有很大概率出现fragment重叠的现象。
一、Fragment 重叠原因分析
切换到其他APP时,Android由于内存资源紧张,fragmen所在activity已经被销毁,但是保存了activity的状态:
Android有一个种特殊情况,就是app运行在后台的时候,内存资源紧张的时候导致把app的资源全部回收(销毁Activity),这时把app再从后台返回到前台时,app会重启Activity。
这属于非正常销毁,尽管Activity实例被销毁,但系统会调用Activity的onSaveInstanceState()保存其状态,这样,如果用户导航回该Activity,系统会使用onCreate中的参数savedInstanceStatea保存的状态数据恢复之前的fragment,并重新创建activity新实例,这样相当于又再次add了fragment进去,所以出现了重叠现象。
二、解决方案:(亲测有效)
findFragmentbyTag:
即在add()或replace()时绑定一个tag,一般用fragment的类名作为tag,然后在发生“内存重启”时,通过findFragmentByTag()
找到对应的Fragment显示show(),并hide()需要隐藏的fragment。
/*2、解决内存重启后碎片的重叠问题 */
private void initFragmen(Bundle savedInstanceState)
{
if(savedInstanceState != null)
{
// “内存重启”时调用
homepageFragment = (HomepageFragment)getSupportFragmentManager().findFragmentByTag("homepageFragment");
hotFragment = (HotFragment)getSupportFragmentManager().findFragmentByTag("hotFragment");
meFragment = (MeFragment)getSupportFragmentManager().findFragmentByTag("meFragment");
//取出onSaveInstanceState(Bundle outState)里保存离开时的那个界面的tag,恢复到用户离开时的那个Fragment的界面
String tag = savedInstanceState.getString("lastVisibleFragment");
switch (tag)
{
case "homepageFragment":
// 解决重叠问题
getSupportFragmentManager().beginTransaction()
.show(homepageFragment)
.hide(hotFragment)
.hide(meFragment)
.commit();
break;
case "hotFragment":
// 解决重叠问题
getSupportFragmentManager().beginTransaction()
.show(hotFragment)
.hide(homepageFragment)
.hide(meFragment)
.commit();
topView.setVisibility(View.GONE);
toolbar.setVisibility(View.GONE);
break;
case "meFragment":
// 解决重叠问题
getSupportFragmentManager().beginTransaction()
.show(meFragment)
.hide(hotFragment)
.hide(homepageFragment)
.commit();
topView.setVisibility(View.GONE);
toolbar.setVisibility(View.GONE);
break;
}
}
else
{
// 正常创建时
homepageFragment = new HomepageFragment();
hotFragment = new HotFragment();
meFragment = new MeFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.content_fragment_layout,homepageFragment, "homepageFragment")
.add(R.id.content_fragment_layout,hotFragment,"hotFragment")
.add(R.id.content_fragment_layout,meFragment,"meFragment")
.show(homepageFragment)
.hide(hotFragment)
.hide(meFragment)
.commit();
}
}
三、恢复到用户离开时的那个Fragment的界面
如果你想恢复到用户离开时的那个Fragment的界面,你还需要在onSaveInstanceState(Bundle outState)
里保存离开时的那个界面的tag或者下标,在“内存重启”代码块中,取出tag/下标,进行恢复。
/*5、内存销毁活动后,保存ctivity中当前显示的fragment的tag*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
lastVisibleFragment = getVisibleFragment();
outState.putString("lastVisibleFragment",lastVisibleFragment.getTag());
}
四、得到Activity当前显示的fragment
/*6、得到当前Activity显示的fragment*/
private Fragment getVisibleFragment()
{
Fragment lastFragment = null;
fragmentManager = getSupportFragmentManager();
fragmentList = fragmentManager.getFragments();
for(Fragment fragment : fragmentList)
{
if (fragment != null && fragment.isVisible())
{
lastFragment = fragment;
break;
}
}
return lastFragment;
}