最近在开发过程中使用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(); } }