1、问题描述
使\应用使用越来越慢,主要表现在切换tab bar时,页面切换卡顿明显
2、问题分析
- 主界面布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/pageBg" android:orientation="vertical" > <FrameLayout android:id="@+id/details" android:layout_marginBottom="60dp" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <fragment android:id="@+id/table" android:layout_marginTop="-60dp" android:layout_width="fill_parent" android:layout_height="fill_parent" android:name="com.synnex.neighborhood.ui.TableBarFragment" /> </LinearLayout> |
- 底部导航栏TableBarFragment实现页面切换,核心源码如下:
public void changeFragment(int index) { FragmentTransaction fragmentTransaction = fragmentManager .beginTransaction(); android.support.v4.app.Fragment otherdesc = getFragmentManager().findFragmentById( R.id.details); if (otherdesc != null && otherdesc.isVisible()) { fragmentTransaction.remove(otherdesc); fragmentTransaction .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); } TempData.fragmentNo = index; tempIndex = index; switch (index) { case 0: cutIndex = 0; agmentNew newIndex = new IndexFragmentNew(); fragmentTransaction.replace(R.id.details, newIndex); break; case 1: cutIndex = 1; IntetractsMainFragment searchIntent = new IntetractsMainFragment(); fragmentTransaction.replace(R.id.details, searchIntent); break; case 2: cutIndex = 2; PropertyMainFragmentNew propertyIntent = new PropertyMainFragmentNew(); fragmentTransaction.replace(R.id.details, propertyIntent); break; case 3: cutIndex = 3; if(changeLifeAroundVersion){ LifeAroundTypeNewFragment LifeAroundIntent = new LifeAroundTypeNewFragment(); fragmentTransaction.replace(R.id.details, LifeAroundIntent); }else if(changeLifeAroundVersion20150310){ mLifeAroundTypeListNewFragment = new LifeAroundTypeListNewFragment(); mLifeAroundTypeListNewFragment.mCallback = this; fragmentTransaction.replace(R.id.details, mLifeAroundTypeListNewFragment); } else{ LifeAroundTypeFragment LifeAroundIntent = new LifeAroundTypeFragment(); fragmentTransaction.replace(R.id.details, LifeAroundIntent); } break; case 4: cutIndex = 4; MineFragment mineFragment = new MineFragment(); fragmentTransaction.replace(R.id.details, mineFragment); break; default: break; } fragmentTransaction.commitAllowingStateLoss(); } |
我们在处理页面切换的时候会将对应模块的Fragement replace,replace 后会将Fragement彻底删除,下次切换回来的时候,Fragement需要重新创建,Fragement没有重用这种效率特别低,就会导致以上切换卡顿的问题。可能会有同学提出为什么不将Fragement添加到BackStack,我们可以这么做但无法实现我们想要的功能,BackStack适用于我们按back 键的时候将Fragment回退,否则按back键,应用会退出当前activity,
如果我们想在一个activity中放置多个Fragement,且按back键能顺序退出类似于退activity这种类似功能我们可以使用该属性。
作为底部导航栏,我们希望切换tab时对应的界面能够迅速的加载出来,中间没卡顿而不是退出的时候顺序退出。该如何实现了?
3、解决方案
其实Fragement的切换除了replace外官方提供了另外的方式。
show 和 add,当Fragement 已经创建需要显示时调用show方法,其他模块的Fragement 则hide;如果Fragement 没有创建则创建该Fragement并调用add方法添加到需要显示的区域。这种方式的好处是当我们加载过一次Fragement后,以后切换会特别流畅,原因是它不需要重新去创建将所有视图重新初始化。这样即可解决切换问题。
FragmentTransaction fragmentTransaction = fragmentManager .beginTransaction(); hideFrgement(fragmentTransaction) ;//隐藏其他模块的Fragement TempData.fragmentNo = index; tempIndex = index; switch (index) { case 0: cutIndex = 0; if(newIndex!=null){ fragmentTransaction.show(newIndex); }else { newIndex = new IndexFragmentNew(); fragmentTransaction.add(R.id.details, newIndex); } break; case 1: cutIndex = 1; if(searchIntent!=null){ fragmentTransaction.show(searchIntent); }else { searchIntent = new IntetractsMainFragment(); fragmentTransaction.add(R.id.details, searchIntent); } break; case 2: cutIndex = 2; if(propertyIntent!=null){ fragmentTransaction.show(propertyIntent); }else { propertyIntent = new PropertyMainFragmentNew(); fragmentTransaction.add(R.id.details, propertyIntent); } break; case 3: cutIndex = 3; if(mLifeAroundTypeListNewFragment!=null){ fragmentTransaction.show(mLifeAroundTypeListNewFragment); }else { mLifeAroundTypeListNewFragment = new LifeAroundTypeListNewFragment(); mLifeAroundTypeListNewFragment.mCallback = this; fragmentTransaction.add(R.id.details, mLifeAroundTypeListNewFragment); } break; case 4: cutIndex = 4; if(mineFragment!=null){ fragmentTransaction.show(mineFragment); }else { mineFragment = new MineFragment(); fragmentTransaction.add(R.id.details, mineFragment); } break; default: break; } fragmentTransaction.commitAllowingStateLoss(); |
当然有利必有弊,这种方案其实是典型的空间换时间,将Fragement缓存到内存中,如果我们的模块过多有10多个或者几十个Fragement,这可能会导致oom等类似问题。如果我们的应用没有复杂到这个量级其实是完全没有问题的。当然应用本身也需要做一些内存的优化和管理。