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个回答足以做出结论。 通常具有这些趋势的示例处理场景是: 财务,保…

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/"这下面一行的路径名改成目…

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

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

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

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

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

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

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

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

生产中的性能分析

生产中的性能分析 如果您在Java应用程序的性能方面遇到了一些严重问题,那么很可能您会知道线程分析的价值。 但是您知道应该使用哪个分析器吗? 探查器使用两种基本技术-采样和仪器。 采样分析器 采样探查器包括定期向JVM询问所有当前活动线程的当前执行…

mysql用com_MySQL 使用教程

关于 MySQLMySQL 是最流行的开源数据库。本文简明的讲解了 MySQL 如何下载安装到使用的整个过程。MySQL 支持多种特性:使用 C和 C编写,并使用了多种编译器进行测试,保证了源代码的可移植性。支持 AIX、FreeBSD、HP-UX、Linux、Mac OS、Novell…

c++ 一维数组长度_每天一点C / 一维数组和指针

哈喽,我是老吴,继续记录我的学习心得。每天一点系列是我对微习惯的践行。现在能做到每天一点 C,将来就会有更多的每天一点系列,没人规定嵌入式软件工程师就只能学习 C 语言和折腾 Linux,不要给自己设限。为什么是每天一…

mysql事务中怎么更改空值_MySQL事务

1.事务1.事务特性--ACIDAtomicity(原子性):要么全做,要么不做,不能只做一半(银行转账)Consistency(约束性):事务的前后,约束都能满足Isolation(依赖性):事务之间是独立的,互不影响的Durability(持久性):事务执行之后,事物的结果可以持久保存2.事务隔离级别:read uncommitted:可…

线程池实现填充短信_填充一个池需要多少个线程?

线程池实现填充短信在最近几个月中,我们一直看到很小但持续的操作失败,但有一个奇怪的异常– org.springframework.jdbc.CannotGetJdbcConnectionException –“无法获得JDBC连接; 嵌套异常是java.sql.SQLException:客户端尝试检出…

jsf标签_多个动态包含一个JSF标签

jsf标签每个JSF开发人员都知道ui&#xff1a;include和ui&#xff1a;param标签。 您可以包括一个facelet&#xff08;XHTML文件&#xff09;并传递一个对象&#xff0c;该对象将在包含的facelet中可用&#xff0c;如下所示&#xff1a; <ui:include src"/sections/co…

spring 长轮询_Spring集成文件轮询和测试

spring 长轮询我最近实施了一个小项目&#xff0c;在该项目中&#xff0c;我们必须轮询文件夹中的新文件&#xff0c;然后在文件内容上触发服务流。 Spring Integration非常适合此要求&#xff0c;因为它带有一个通道适配器 &#xff0c;该适配器可以扫描文件夹中的新文件&…

您将在下一个项目中使用JSF吗?

上周有一篇很棒的stackoverflow博客文章&#xff0c;主题是“ JavaScript框架的残酷生命周期” 。 这篇文章是关于Javascript UI框架&#xff08;angularjs&#xff0c;angular&#xff0c;jquery和react&#xff09;的流行和流行的速度。 这篇文章的关键指标是每月关于框架的问…

使用java自带的日志管理_java日志管理

1.相关概念日志统一框架(日志门面)&#xff1a;apache commons logging、slf4j日志实现框架(实现层)&#xff1a;JDK自带的logging(java.util.logging)、log4j、Java Util Logging、log4j2、logback.(1)JDK自带的logging(java.util.logging)用法&#xff1a;1 importjava.util.…

安卓4.4玩java_Android4.4运行过程中闪退java.lang.NoClassDefFoundError

上周五项目测试时发现一个奇怪的Bug&#xff0c;项目中依赖了一个第三方框架&#xff0c;但是在android4.0-4.4.4之间的系统中运行会直接闪退&#xff0c;抛出错误异常为java.lang.NoClassDefFoundError。第一次遇到这样的问题&#xff0c;google了好久找到了以下几个原因&…

update se_Java SE 7 Update 25 –发行说明进行了解释。

update se昨天是CPU日。 Oracle通过6月的Java重要补丁更新发布了Java SE更新25 。 在4月的最后一次重大更新之后&#xff0c;这是最后一次与Oracle其他所有Oracle产品都不适合的Oracle重要补丁更新计划。 从2013年10月开始 &#xff0c;Java安全修补程序将遵循四个年度安全发布…

java scavenge_请概述一下Java中都有哪些垃圾收集器

1、Serial(串行GC)收集器Serial收集器是一个新生代收集器&#xff0c;单线程执行&#xff0c;使用复制算法。它在进行垃圾收集时&#xff0c;必须暂停其他所有的工作线程(用户线程)。是Jvmclient模式下默认的新生代收集器。对于限定单个CPU的环境来说&#xff0c;Serial收集器由…