最近开发应用有这么一个需求,需要监听app的生命周期,能够感知到用户划到后台,回到前台这些事件。
Google以及帮我们实现好了,只需在项目中引入依赖
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
然后自定义一个 LifecycleObserver,在这里面实现生命周期事件对应的响应逻辑。
object AppLifecycleObserver : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
when (event) {
Lifecycle.Event.ON_RESUME -> {}
Lifecycle.Event.ON_STOP -> {}
}
}
}
在Application初始化时,注册这个LifecycleObserver
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver)
现在就可以轻松的监听App生命周期了。
按理说,软件逻辑应该是这样:当用户退到后台后,执行onStop方法。当用户切换回来时,执行onResume方法。
但是在测试的时候发现了这么一个问题,当退出应用又立马切回来的时候,并不会调用onStop和onResume方法。反反复复试了好几遍,就是存在这个问题,当切换的时间太短时,就监听不到了。这..这..这不对吧,我看今天是谁...谁要陷害我?
当我打开了ProcessLifecycleOwner的源码查看时,一个大大的TIMEOUT_MS映入眼帘。
好家伙,我就说怎么回事,原来还有个延时。
仔细研究一下源码。
ProcessLifecycleOwner通过ContentProvider来获取Application
然后通过对Application注册Activity的生命周期的回调来监听Activity的生命周期。
阅读源码后发现
在进行onPause 操作时,会进行延迟通知
并且通知时还会进行判断是否目前需要进行通知。
那么谷歌在这个地方这么做了一个延时是为什么呢?是为了防止用户误操作吗?
当我试图自己手写一个ProcessLifecycleOwner的时候,我才终于明白,原来这压根就是个技术问题。
我们的原理是监听Activity的生命周期,而当你在app内部新开一个Activity或者销毁Activity时,都会引起Activity调用onPause,onStop这些方法。所以,当ProcessLifecycleOwner接受到onPause,onStop这些事件时,并不知道是来自用户退到后台,还是来自app内部的Activity变化。
因此,这里才设置了一个延时,如果是app内部Activity变动,那么一个Activity的onPause必然会伴随另一个Activity的onResume。
这里说一下Activity启动和销毁时以及退到桌面时的生命周期事件:
在A中启动B:
A: onPause
B: onCreate
B: onStart
B: onResume
A: onStop
销毁B,回到A
B: onPause
A: onRestart
A: onStart
A: onResume
B: onStop
B: onDestroy
从app退到桌面:
onPause
onStop
由此可知,无论是哪种情况,onPause方法都会最先被调用,如果太长时间没有调用onResume,就认为是退到后台,如果很快onResume就被调用了,那就认为这只是app内部的activity在变化。这就是设置延时的作用。
终于破案了!原来安卓系统根本就没有提供app生命周期的接口,用监听Activity生命周期的方式来实现会有监听到onPause但是不知道是来自app内部Activity变化还是来自用户退到后台的问题。
解决方案
1、重写ProcessLifecycleOwner,将延时自己缩短点(谷歌官方定的是700毫秒),但也不能缩太短,否则可能新打开一个Activity都会被以为是滑到了后台。
2、自定义一个ProcessLifecycleOwner,在内部实现一个免除的信号量,当你在这个app内部要启动或者销毁Activity时,把这个信号量加一个。在ProcessLifecycleOwner中监听到onPause时,信号量为0则这个事件是来自系统的。信号量>0则这个事件是app内部的,这时不调用app的onPause方法,同时减去1,表示这次的免除机会已经被消费掉。
3、去求一下官方加一个app前后台切换的接口。
————————————————
版权声明:本文为CSDN博主「水夸夸的梁郭先生」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Hunter_chemistry/article/details/123191580