最近在开发过程中使用Fragment做很常见的类微信界面,底部四个可选项,首页、课程、发现和我的,每点击其中一个,在上方显示不同的Fragment,如下图:
起初我并没有考虑太多,用了最简单的方式,直接使用replace方法,代码如下:
getSupportFragmentManager().beginTransaction().replace(R.id.rl_main_content, fragment)
.commit();
后来别人看我代码的时候,说我这样用会重复创建Fragment界面,浪费资源,如果涉及网络请求,还会重复请求,消耗用户流量,用户体验会很差。
于是,我写了个例子打log看看在使用replace的时候,Fragment究竟走了哪些生命周期,log如下:
从log中我们可以看出,用replace的方式切换Fragment时,会把Fragment的完整生命周期走一遍,这就让人不能忍了,我的需求是会多次在Fragment之间切换的,如果每次都重走Fragment生命周期,的确是会浪费资源,消耗流量的。
接着我又找到另一种方式,add()-->detach()-->attach():
getSupportFragmentManager().beginTransaction().detach(fragment);
getSupportFragmentManager().beginTransaction().attach(fragment);
这种方式是先调用add()方法并给Fragment传入唯一的Tag,将Fragment加入它的管理类中,接着我们调用detach()方法,解除当前Fragment与Activity的关联,然后用管理类的findFragmentByTag()方法通过Tag来找到我们要的Fragment,最后调用attach()方法将其与Activity关联,代码如下:
private Fragment currentFragment;
private void replaceFragment(String tag) {
if (currentFragment != null) {
getSupportFragmentManager().beginTransaction().detach(currentFragment).commit();
}
currentFragment = getSupportFragmentManager().findFragmentByTag(tag);
if (currentFragment == null) {
switch (tag) {
case "home":
currentFragment = new HomeFragment();
break;
case "lesson":
currentFragment = new LessonFragment();
break;
case "discover":
currentFragment = new DiscoverFragment();
break;
case "mine":
currentFragment = new MineFragment();
break;
}
getSupportFragmentManager().beginTransaction().add(R.id.rl_main_content, currentFragment, tag).commit();
}else {
getSupportFragmentManager().beginTransaction().attach(currentFragment).commit();
}
}
log如下:
我们从log中可以看出,再次切换至HomeFragment时没有调用onAttach和onCreate方法,说明这种方式减少了生命周期的调用,也算是提升了一些性能。
不过我们还有一种方式,可以完全不重新调用任何一个生命周期函数,add()-->hide()-->show()-->:(代码基本和上面一样,只是把attach改为show,dettach改为hide)
private void replaceFragment(String tag) {
if (currentFragment != null) {
getSupportFragmentManager().beginTransaction().hide(currentFragment).commit();
}
currentFragment = getSupportFragmentManager().findFragmentByTag(tag);
if (currentFragment == null) {
switch (tag) {
case "home":
currentFragment = new HomeFragment();
break;
case "lesson":
currentFragment = new LessonFragment();
break;
case "discover":
currentFragment = new DiscoverFragment();
break;
case "mine":
currentFragment = new MineFragment();
break;
}
getSupportFragmentManager().beginTransaction().add(R.id.rl_main_content, currentFragment, tag).commit();
}else {
getSupportFragmentManager().beginTransaction().show(currentFragment).commit();
}
}