android 为什么fragment在调用hide方法后没有生效_Android 多 Fragment 切换优化

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时发生了以下的生命周期:

f712df5ab0f6124cd54b90f0dd4601b2.png
image

想想看每次都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 fragments = manager.getFragments();for (Fragment fragment : fragments) {if (fragment != currentFragment && !fragment.isHidden()) {
            transaction.hide(fragment);
        }
    }
}

略微解释一下:

先查询fragmentManager 所在的activitiy 中是否已经添加了这个fragment
第一步 先从一个mAdded 的一个ArrayList遍历查找,如果找不到再从 一个 叫 mActive 的 SparseArray的一个map里面查找。

注意:

  1. 一个 fragment 被 remove 掉后,只会从 mAdded 里面删除,不会从 mActive 里面删除,只有当这个fragment 所在的 transaction 从回退栈里面移除后才会 从mActive 删除

  2. 当我们add 一个fragment时 会把我们的fragment 添加到 mAdded 里面,不会添加到 mActive。

  3. 只有当我们把 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 权限适配手记

b616e0a32cb700becf6fa74eb7b0f41f.png

不怕巨人高

就怕巨人还要踩在巨人肩膀上

这样就很难超越了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348092.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql如何查看远程用户_MySQL系列(十)--用户权限及远程访问

本文基于MySQL8.0,记录一下完整的远程访问的过程,以及这个过程中可能遇到的问题,MySQL运行在阿里云服务器,操作系统:CentOS 7.6 64位顺便说下,买服务器还是要双十二这种拉新活动再买,用一个新的…

spring mvc拆分_Spring集成–强大的拆分器聚合器

spring mvc拆分健壮是什么意思? 在本文的上下文中,健壮性是指在不立即返回给调用者的情况下管理流中的异常条件的能力。 在某些处理方案中, n个 m个回答足以做出结论。 通常具有这些趋势的示例处理场景是: 财务,保…

mysql typeindex_explain mysql的type字段,索引的类型

4.type这列很重要,显示了连接使用了哪种类别,有无使用索引.从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL(1).system这是const联接类型的一个特例。表仅有一行满足条件.如下(t3表上的id是 primary key)mysql> explain select * from (select * from t3 …

JasperReports:棘手的部分

如果您使用Java进行编程的时间足够长,则有可能需要为业务用户生成报告。 就我而言,我已经看到几个项目使用JasperReports库来生成PDF和其他文件格式的报告。 最近,我荣幸地观察了Mike和他的团队使用上述报告库及其面临的挑战。 简而言之Jasp…

win mysql 2003错误_windows MySql 报1067错误 2003错误

1067错误原因是我把安装mysql的目录的名字改了。但是位于目录里面的my.ini配置文件没有修改,玛德我真傻逼。把my.ini的#Path to installation directory. All paths are usually resolved relative to this.basedir"D:/My_MySQL/"这下面一行的路径名改成目…

java heroku_Heroku和Java –从新手到初学者,第1部分

java heroku最近,我听说Heroku允许在Cedar堆栈中部署Java应用程序。 由于没有真正的软件构想,我决定尝试一下,仅配置SOMETHING以在Heroku上运行。 我对ReST有所了解(我仍然想学习并练习),所以我决定我的第…

mysql 合服_风云私服合区的方法详解(mysql数据库合并)

只能合并帐号,MY的库不能合并。倒数据前请留好备份,防止发生以外,破坏你得数据,切忌.1)首先确认你的机器上必须装MySQL 以及 mysql-connector-odbc-5.1.1-win32.msimysql-connector-odbc-5.1.1-win32.msi 就是 MySQL ODBC 5.1,你可…

mysql自定义数据类型_MySQL中的数据类型

一.MySQL中的数值类型分类MySQL中数值类型主要有三类:数字类型,字符串类型,时间类型。1.数字类型1.1整数tinyint 1字节smallint 2字节mediumint 3字节int 4字节bigint …

分布式系统开发注意点_分布式系统开发注意事项

分布式系统开发注意点开发分布式软件系统时,要考虑许多因素。 如果您甚至不知道第一句话中我在说什么,那么让我为您提供一些见解,示例以及有关分布式系统的实例。 总览 分布式系统是指多个物理硬件设备与单独的离散用户交互并通过这些硬件设…

String#repeat来到Java吗?

JDK-8197594 (“ String#repeat”)在其“描述”中包括以下内容:“长期以来,一直要求一种用于重复字符序列的String方法,没有后续操作。” 可以在JDK-8197594的“问题链接”中找到有关String类中用于重复字符…

mysql 什么是幻读_何为幻读?MySQL又是如何解决幻读的?

一、什么是幻读在一次事务里面,多次查询之后,查询的结果集的个数不一致的情况叫做幻读。而多出来或者少的哪一行被叫做 幻行二、为什么要解决幻读在高并发数据库系统中,需要保证事务与事务之间的隔离性,还有事务本身的一致性。三、…

电子电气架构——车载ECU刷写工具vFlash简介

电子电气架构——车载ECU刷写工具vFlash简介 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值&a…

mysql执行系统命令_mysql 命令行执行 sql

1.直接输入sql执行MySQL> select now();---------------------| now() |---------------------| 2013-09-18 13:55:45 |---------------------1 row in set (0.00 sec)2.执行编写好的sql脚本mysql> source /home/1.sql---------------------| now() |-------------------…

jboss7.1.1 部署_在JBoss AS 7上部署BroadleafCommerce 2.0

jboss7.1.1 部署前2个步骤实际上与Broadleaf无关&#xff0c;但是提到该步骤是为了使其易于执行&#xff08;复制/粘贴&#xff09;这些步骤。 步骤&#xff03;1&#xff1a;在JBoss AS中配置数据源。 <datasource jta"true" jndi-name"java:jboss/datasou…

java中n次方怎么表示_java如何计算一个数的n次方

java递归算法&#xff0c;代码如下&#xff1a;public class Test3 { public double zhishu(double x,double y){ if(y>0){ return x*zhishu(x,y-1); }else if(y<0){ return (x*zhishu(x,-y-1)); }else{ return 1; } } public double fuzhishu(…

枚举集合的EnumSet

在上一篇博客文章中&#xff0c;我们发现了EnumMap用于带有枚举键的映射。 您可能已经观察到&#xff0c;还有一个专门针对枚举优化的Set &#xff1a; EnumSet 。 我们再次定义一个CoffeeType枚举&#xff1a; public enum CoffeeType {ESPRESSO, POUR_OVER, FRENCH_PRESS, …

linux下mkdir头文件_Linux中判断一个目录是否存在,如果不存在就创建这个目录

在操作文件目录时我们常常会考虑如下的功能&#xff1a;1、判断文件是否存在&#xff0c;并判断文件是否可写/目录是否存在Linux下&#xff1a;#includeint access(const char* pathname, int mode);参数介绍&#xff1a;返回值&#xff1a;成功0&#xff0c;失败-1pathname 是…

mac 连接hbase的图形化界面_MAC安装Hbase以及Hbase基本命令

安装Hbase1&#xff0e;官网下载安装包&#xff0c;我下载的是hbase-2.4.0-bin.tar.gz。2&#xff0e;解压&#xff1a;tar zxf hbase-2.4.0-bin.tar.gz3&#xff0e;安装JDK&#xff0c;并设置JAVA_HOME&#xff0c;通过vi ~/.bash_profile&#xff0c;设置环境变量export JAV…

ldap java_使用LDAP保护Java EE6中的Web应用程序

ldap java在上一篇文章中&#xff0c;我们解释了如何在通过传输层安全性&#xff08;TLS&#xff09;/安全套接字层&#xff08;SSL&#xff09;传输数据时保护数据。 现在让我们尝试了解如何为使用LDAP服务器进行身份验证的基于JEE 6的Web应用程序应用安全机制。 目的&#x…

mysql 一致性hash_一致性hash算法在分表分库中的应用

一致性hash算法结构图 分表分库结构图 可进行循环冗余存储&#xff0c;顺时针存储到下一个物理节点(非虚拟节点)package com.haiziwang.platform.kmcsms.route.algorithm;import java.util.Collection;import java.util.SortedMap;import java.util.TreeMap;/*** 一致性Hash算法…