之前写过一篇关于Fragment真正的onResume与onPause的文章,但是当时写的比较匆忙,并不是很严谨,导致问题多多,今天抽空更新下关于fragment在各种情况下的onResume与onPause的方法,首先附一张fragment的生命周期图:

1. fragment通过replace方式使用

fragment在该方式中使用,使用周期基本与图上的生命周期一样,onResume与onPause就正常使用即可

2. fragment在show/hide方式使用

fragment在该方式中使用的时候,生命周期就开始有区别了,举个栗子:

一个页面效果如图所示,根据底部菜单切换对应的fragment

代码添加fragment:

然后在Fragment的onViewCreated、onResume与onPause中打印log看看执行的顺序:


在点击切换fragment时,onResume与onPause并没有再次执行,从中我们可以发现,show/hide方式切换fragment的时候,fragment是被一次性加载到页面上的,并且都执行了onResume方法,即使当前没有显示出现,那么如果show/hide切换有没有其他的方法执行呢?答案是有的,它就是onHiddenChanged(boolean hidden)方法,然后我们在该方法里加入log看下情况:


从上图可以看出,除了刚开始执行过onResume方法,点击切换时,只执行了onHiddenChanged方法,如果要在show/hide中实现类似onResume/onPause的生命周期该怎么做呢?

继续从上图找规律,我们发现:

刚进入页面时,除了首页,其他三个页面都是先执行的onHiddenChanged方法,参数为true,也就是隐藏,然后才一起执行的onResume方法,那么我们需要怎么做呢?看代码:

定义两个变量,默认为false

    //是否运行onHiddenChanged方法isRuningHiddenChanged = false//是否可见isUserVisible = false override fun onResume() {super.onResume()Log.e(TAG, "$mTag ===  onResume")//如果没有执行onHiddenChanged方法,则是第一个fragmentif(!isRuningHiddenChanged){isRuningHiddenChanged = true//记录页面可见状态isUserVisible = trueonUserVisible()}}override fun onHiddenChanged(hidden: Boolean) {super.onHiddenChanged(hidden)//如果是隐藏if(hidden){//如果当前fragment已经页面可见了,那么就要执行不可见方法if (isUserVisible){isUserVisible = falseonUserInvisible()}} else {//如果是显示onUserVisible()//记录页面可见状态isUserVisible = true}isRuningHiddenChanged = true}fun onUserVisible(){Log.e(TAG, "$mTag ===  onUserVisible")}fun onUserInvisible(){Log.e(TAG, "$mTag ===  onUserInvisible")}

好了, 让我们再次执行下看下生命周期:

通过log可以看出来,我们成功的找到了show/hide时fragment的模拟“onResume”与“onPause”的生命周期方法,当然,如果你觉得这么就结束了,那么还早了点,比如我们启动新页面和新页面返回呢?,废话少说,上log:


咦?怎么启动新页面和返回来并没有执行onHiddenChanged方法,而是所有fragment都执行了onPause和onResume,那么我们还需要在这两个方法里进行一些判断,可以在onPause和onResume根据isUserVisible==true区分当前fragment是否显示,代码如下:

    override fun onResume() {super.onResume()if(!isRuningHiddenChanged){isRuningHiddenChanged = trueisUserVisible = trueonUserVisible()} else {//如果当前页面可见的if (isUserVisible) {onUserVisible()}}}override fun onPause() {super.onPause()//如果当前页面可见的if (isUserVisible) {onUserInvisible()}}

ok,继续运行,打印log:

nice!完善了fragment使用show hide时的模拟“onResume”与“onPause”的生命周期方法!

3. fragment在Viewpager中使用

同样,还是这个例子:

只不过我们切换时使用的是viewpager,先看下刚进入页面和切换的生命周期:


发现这里的生命周期好乱啊,完全无从下手,那么如果也使用show/hide用到的onHiddenChanged方法呢?经过实验发现根本就不走onHiddenChanged方法,那怎么办呢?经过搜索发现,fragment在viewpager中会执行setUserVisibleHint(boolean isVisibleToUser)方法,那么我们在该方法中加入log看一下:


由于viewpager只会保留三个页面的情况就不多说了,我们只观察执行情况,从中寻找规律,默认先会执行setUserVisibleHint方法,这样肯定不对,必须保证 我们的onUserVisible是在view创建之后执行,onUserInvisible在调用onUserVisible之后再执行,那么这一块逻辑比较复杂,大家可以看代码:

    private var isFirstResume = trueprivate var isFirstVisible = trueprivate var isUserVisible = falseprivate var isPrepared: Boolean = falseoverride fun onResume() {super.onResume()if (isFirstResume) {isFirstResume = falsereturn}if (userVisibleHint) {isUserVisible = trueonUserVisible()}}override fun onPause() {super.onPause()if (isFirstResume) {isFirstResume = falsereturn}if (userVisibleHint) {if(isUserVisible){isUserVisible = falseonUserInvisible()}}}override fun onActivityCreated(savedInstanceState: Bundle?) {super.onActivityCreated(savedInstanceState)initPrepare()}override fun setUserVisibleHint(isVisibleToUser: Boolean) {super.setUserVisibleHint(isVisibleToUser)if (isVisibleToUser) {if (isFirstVisible) {isFirstVisible = falseinitPrepare()} else {isUserVisible = trueonUserVisible()}} else {if(isUserVisible){isUserVisible = falseonUserInvisible()}}}private fun initPrepare() {if (isPrepared) {isUserVisible = trueonUserVisible()} else {isPrepared = true}}open fun onUserVisible() {Log.e(ViewPagerFragment.TAG, "$mTag ===  onUserVisible")}open fun onUserInvisible() {Log.e(ViewPagerFragment.TAG, "$mTag ===  onUserInvisible")}override fun onDestroyView() {super.onDestroyView()isFirstResume = trueisFirstVisible = trueisUserVisible = falseisPrepared = false}

执行,打印log:


ok!没问题,那么启动新页面和返回呢?试试:

通过log可以看出来,并没有问题,我们成功的找到了viewpager时fragment的模拟“onResume”与“onPause”的生命周期方法!

结尾

ok,教程到这里就该结束了,下面是代码大家可以参考一下:

Demo下载地址

Android 再次探究Fragment在各种情况下的onResume与onPause相关推荐

  1. Android 锁屏,息屏情况下打开界面Activity类似微信视频通话接电话时弹出接电话的界面

    Android 锁屏,息屏情况下打开界面Activity,类似微信视频通话接电话时弹出接电话的界面 https://blog.csdn.net/yingtian648/article/details/ ...

  2. android studio 插件开发 FindByTag插件 局部情况下取代ButterKnife插件

    貌似ButterKnife在多模块使用的时候不是很友好,并且并没有现成的插件可以使用,所以就适当看了看怎么使用插件动态生成FindByTag,我当前使用的框架(当然不是我开发的,在感谢表中会列出框架地 ...

  3. android imageview 锯齿,android – 如何在启用消除锯齿的情况下旋转drawable

    如果您知道Drawable是BitmapDrawable,则可以在位图的Paint中使用消除锯齿来执行以下操作: /** * Not as full featured as ImageView.onD ...

  4. appium的输入法appium android input manager for unicode有些情况下无法输入文本信息

    这是因为appium输入法会收起键盘,有些输入框控件时会判断键盘打开才能聚焦控件输入信息,与appium输入法矛盾导致无法正常输入文本 目前解决方法只能切换成其他输入法.

  5. android 弹出fragment,Android中ViewPager获取当前显示的Fragment

    前言 在项目中,有时会用到在ViewPager中显示同样类型的Fragment,同时这样的Fragment的个数是动态的,但是PagerAdapter没有给我们提供getCurrentFragment ...

  6. android调用fragment的方法,AndroidX下使用Activity和Fragment的变化

    原标题:AndroidX下使用Activity和Fragment的变化 原文:How AndroidX changes the way we work with Activities and Frag ...

  7. 如何在没有 USB 数据线的情况下使用 Android Studio 在手机中安装 Android

    背景 如何在没有 USB 数据线的情况下使用 Android Studio 在手机中安装 Android 应用程序? 运行调式一个Android项目,写下必要的代码后,接下来的任务是在模拟器或手机上运 ...

  8. android弹出选择usb,android 解决:默认情况下用于该USB设备 自动获取USB操作权限...

    很多android 的应用在使用USB设备时,总会遇到一个很烦人的问题. 即每次都会弹出对话框: 每次插入USB设备,都会弹出.每次选上默认情况下使用该USB设备.但总还是会弹出.用户体验很差. 似乎 ...

  9. java 定义变量时 赋值与不赋值_探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值...

    探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值 当基本数据类型作为普通变量(八大基本类型: byte,char,boolean,short,int,long,fl ...

最新文章

  1. vim中删除dos格式文件中的^M号的方法以及深度规整文件格式
  2. matlab的syms无法在函数中使用_Python函数中使用@
  3. Dart 2为移动开发做出改进
  4. AndroidStudio动态调试smali
  5. Echarts开源可视化库学习(三)主题的使用
  6. js中单竖杠 | 的作用
  7. Git 之五 通信协议(HTTPS、SSH、Git)、使用远程仓库(GitHub、GitLab、Gitee等)
  8. java安全编码指南之:方法编写指南
  9. mysql注入漏洞语句,web安全之sql注入漏洞
  10. 计算机应用基础重点分析,计算机应用基础整体设计重点分析.doc
  11. 【华为云技术分享】《跟唐老师学习云网络》 - Veth网线
  12. python自动翻译excel某一列_【python excel实例教程】怎样用Python将excel的某一列生成一个列表?...
  13. 怎么把一个gif表情包分解成多个?
  14. 计算机主板虚拟化,启用Lenovo计算机BIOS虚拟化的方法
  15. 通过远程PHP远程调用ZABBIX接口获取数据
  16. 天融信EDR或企业安全终端卸载需要密码解决办法
  17. java 卡牌游戏抽奖。
  18. 装备制造业ERP软件如何帮助企业做好物料齐套管理?
  19. Linux分区命令-parted
  20. PS/2接口鼠标滚轮不能用的解决办法

热门文章

  1. springClound之springCloundConfig
  2. Win10安装提示“我们无法创建新的分区,也找不到现有的分区”的问题解决方案
  3. ES5和ES6继承有何区别
  4. 计算机专业打游戏哪个笔记本好,打游戏的笔记本电脑推荐_2020最强悍的游戏笔记本...
  5. Bucket Join:分桶Join
  6. Java StringTokenizer 类与示例
  7. 格林威克轴承:常见的轴承类型有哪些?
  8. Vue 3.X 结合 arcgis 4.X 加载国内四种在线底图 百度、腾讯、高德、天地图(学不会揍我)
  9. 音频信号介绍以及MATLAB简单处理
  10. 如何保护客户数据并降低合规风险