code小生,一个专注 Android 领域的技术平台
公众号回复 Android 加入我的安卓技术群
作者:DDDong丶链接:https://www.jianshu.com/p/c8e8a0249911声明:本文已获
DDDong丶授权发表,转发等请联系原作者授权
问题分析
一直在简书里看别人的技术贴,今天我也来写点自己的心得!最近在写一个项目用到大量的Fragment后的总结!
我想刚刚接触安卓的同学或许会这么写:
FragmentManager fragmentManager=getSupportFragmentManager();FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();fragmentTransaction.add(ViewId,fragment);// 或者fragmentTransaction.replace(ViewId,fragment);fragmentTransaction.commit();
基础更好一点的同学会用show和hide方法
FragmentManager fm = getSupportFragmentManager();FragmentTransaction ft = fm.beginTransaction();ft.hide(new FirstFragment()) .show(new SecondFragment()) .commit();
诚然这两种都可以切换Fragment,但是面对用户大量点击来回切换,或者你的Fragment本来就很多,每次都这样操作,那么很快你的应用就会OOM,就算不崩那也会异常的卡顿!so why?
当我们replace时发生了以下的生命周期:
想想看每次都replace一下!!这世界会有多美好!!!那么问题出在哪?回过头看看代码就会发现每次在add/replace或者show/hide都会new 一个新的实例,这就是致命原因!!!!!
废话不多说,亮出我的方法(抽取后的):
/** * Fragment的添加 * @param manager Fragment管理器 * @param aClass 相应的Fragment对象的getClass * @param containerId 容器的id * @param args 需要传值的话可将bundle填入 不需要传值就填null */protected void addFragment(FragmentManager manager, Class<? extends BaseFragment> aClass, int containerId, Bundle args) { String tag = aClass.getName(); Logger.d("%s add fragment %s", TAG, aClass.getSimpleName()); Fragment fragment = manager.findFragmentByTag(tag); FragmentTransaction transaction = manager.beginTransaction(); // 开启一个事务 if (fragment == null) {// 没有添加 try { fragment = aClass.newInstance(); // 通过反射 new 出一个 fragment 的实例 BaseFragment baseFragment = (BaseFragment) fragment; // 强转成我们base fragment // 设置 fragment 进入,退出, 弹进,弹出的动画 transaction.setCustomAnimations(baseFragment.enter(), baseFragment.exit(), baseFragment.popEnter(), baseFragment.popExit()); transaction.add(containerId, fragment, tag); if (baseFragment.isNeedToAddBackStack()) { // 判断是否需要加入回退栈 transaction.addToBackStack(tag); // 加入回退栈时制定一个tag,以便在找到指定的事务 } } catch (Exception e) { e.printStackTrace(); } } else { if (fragment.isAdded()) { if (fragment.isHidden()) { transaction.show(fragment); } } else { transaction.add(containerId, fragment, tag); } } if (fragment != null) { fragment.setArguments(args); hideBeforeFragment(manager, transaction, fragment); transaction.commit(); }}/** * 除当前 fragment 以外的所有 fragment 进行隐藏 * * @param manager * @param transaction * @param currentFragment */private void hideBeforeFragment(FragmentManager manager, FragmentTransaction transaction, Fragment currentFragment) { List<Fragment> fragments = manager.getFragments(); for (Fragment fragment : fragments) { if (fragment != currentFragment && !fragment.isHidden()) { transaction.hide(fragment); } }}
略微解释一下:
先查询fragmentManager 所在的activitiy 中是否已经添加了这个fragment第一步 先从一个mAdded 的一个ArrayList遍历查找,如果找不到再从 一个 叫 mActive 的 SparseArray的一个map里面查找。
注意:
-
一个 fragment 被 remove 掉后,只会从 mAdded 里面删除,不会从 mActive 里面删除,只有当这个fragment 所在的 transaction 从回退栈里面移除后才会 从mActive 删除
-
当我们add 一个fragment时 会把我们的fragment 添加到 mAdded 里面,不会添加到 mActive。
-
只有当我们把 transaction 添加到回退栈的时候,才会把我们的 fragment 添加到 mActive 里面。所以我们通过 findFragmentByTag 方法查找出来的 fragment 不一定是被添加到我们的 activity 中。
使用:
代码比较多,但是我个人感觉使用起来比较方便,而且功能也比较完善,使用的时候只需要两行代码:
HomeFragment1 homeFragment = new HomeFragment1();addFragment(getSupportFragmentManager(),homeFragment.getClass(),R.id.main_body,null);
当我们需要传值的时候,只需要将准备好的bundle以参数的形式填入即可。我还增加了一个是否加入回退栈的判断,用于实现一些有关回退栈的需求,实现这个功能还需要在BaseFragment中定义一个方法:
protected boolean isNeedToAddBackStack() { return true;}
也就这么点内容,各位大佬如果看出什么问题或者有什么更好的方法,欢迎大家在下方评论留言。
推荐阅读浅谈 Activity,Fragment 模块化封装巧用 Fragment,解耦 Android6.0 权限适配手记
不怕巨人高
就怕巨人还要踩在巨人肩膀上
这样就很难超越了