Android 再次探究Fragment在各种情况下的onResume与onPause
之前写过一篇关于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相关推荐
- Android 锁屏,息屏情况下打开界面Activity类似微信视频通话接电话时弹出接电话的界面
Android 锁屏,息屏情况下打开界面Activity,类似微信视频通话接电话时弹出接电话的界面 https://blog.csdn.net/yingtian648/article/details/ ...
- android studio 插件开发 FindByTag插件 局部情况下取代ButterKnife插件
貌似ButterKnife在多模块使用的时候不是很友好,并且并没有现成的插件可以使用,所以就适当看了看怎么使用插件动态生成FindByTag,我当前使用的框架(当然不是我开发的,在感谢表中会列出框架地 ...
- android imageview 锯齿,android – 如何在启用消除锯齿的情况下旋转drawable
如果您知道Drawable是BitmapDrawable,则可以在位图的Paint中使用消除锯齿来执行以下操作: /** * Not as full featured as ImageView.onD ...
- appium的输入法appium android input manager for unicode有些情况下无法输入文本信息
这是因为appium输入法会收起键盘,有些输入框控件时会判断键盘打开才能聚焦控件输入信息,与appium输入法矛盾导致无法正常输入文本 目前解决方法只能切换成其他输入法.
- android 弹出fragment,Android中ViewPager获取当前显示的Fragment
前言 在项目中,有时会用到在ViewPager中显示同样类型的Fragment,同时这样的Fragment的个数是动态的,但是PagerAdapter没有给我们提供getCurrentFragment ...
- android调用fragment的方法,AndroidX下使用Activity和Fragment的变化
原标题:AndroidX下使用Activity和Fragment的变化 原文:How AndroidX changes the way we work with Activities and Frag ...
- 如何在没有 USB 数据线的情况下使用 Android Studio 在手机中安装 Android
背景 如何在没有 USB 数据线的情况下使用 Android Studio 在手机中安装 Android 应用程序? 运行调式一个Android项目,写下必要的代码后,接下来的任务是在模拟器或手机上运 ...
- android弹出选择usb,android 解决:默认情况下用于该USB设备 自动获取USB操作权限...
很多android 的应用在使用USB设备时,总会遇到一个很烦人的问题. 即每次都会弹出对话框: 每次插入USB设备,都会弹出.每次选上默认情况下使用该USB设备.但总还是会弹出.用户体验很差. 似乎 ...
- java 定义变量时 赋值与不赋值_探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值...
探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值 当基本数据类型作为普通变量(八大基本类型: byte,char,boolean,short,int,long,fl ...
最新文章
- vim中删除dos格式文件中的^M号的方法以及深度规整文件格式
- matlab的syms无法在函数中使用_Python函数中使用@
- Dart 2为移动开发做出改进
- AndroidStudio动态调试smali
- Echarts开源可视化库学习(三)主题的使用
- js中单竖杠 | 的作用
- Git 之五 通信协议(HTTPS、SSH、Git)、使用远程仓库(GitHub、GitLab、Gitee等)
- java安全编码指南之:方法编写指南
- mysql注入漏洞语句,web安全之sql注入漏洞
- 计算机应用基础重点分析,计算机应用基础整体设计重点分析.doc
- 【华为云技术分享】《跟唐老师学习云网络》 - Veth网线
- python自动翻译excel某一列_【python excel实例教程】怎样用Python将excel的某一列生成一个列表?...
- 怎么把一个gif表情包分解成多个?
- 计算机主板虚拟化,启用Lenovo计算机BIOS虚拟化的方法
- 通过远程PHP远程调用ZABBIX接口获取数据
- 天融信EDR或企业安全终端卸载需要密码解决办法
- java 卡牌游戏抽奖。
- 装备制造业ERP软件如何帮助企业做好物料齐套管理?
- Linux分区命令-parted
- PS/2接口鼠标滚轮不能用的解决办法
热门文章
- springClound之springCloundConfig
- Win10安装提示“我们无法创建新的分区,也找不到现有的分区”的问题解决方案
- ES5和ES6继承有何区别
- 计算机专业打游戏哪个笔记本好,打游戏的笔记本电脑推荐_2020最强悍的游戏笔记本...
- Bucket Join:分桶Join
- Java StringTokenizer 类与示例
- 格林威克轴承:常见的轴承类型有哪些?
- Vue 3.X 结合 arcgis 4.X 加载国内四种在线底图 百度、腾讯、高德、天地图(学不会揍我)
- 音频信号介绍以及MATLAB简单处理
- 如何保护客户数据并降低合规风险