前言
最近开发应用有这么一个需求,需要监听app的生命周期,能够感知到用户划到后台,回到前台这些事件。
方案
一般前后台监听有两种方案:
- 利用 ActivityLifecycleCallbacks 监听所有activity的生命周期
- 使用 ProcessLifecycleOwner
代码实现
方案一:利用 ActivityLifecycleCallbacks 监听所有activity的生命周期
定制前后台切换监听类:ForegroundCallbacks.kt
/**
* 实现方式1:前后台监听
*/
private const val TAG = "ForegroundCallbacks"
class ForegroundCallbacks(private val mOnAppStatusListener: OnAppStatusListener?) :
Application.ActivityLifecycleCallbacks {
// 当前Activity数量
private var activityStartCount = 0
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
APieLog.d(TAG, "onActivityCreated: $activity")
}
override fun onActivityStarted(activity: Activity) {
APieLog.d(TAG, "onActivityStarted: $activity")
activityStartCount++
// 数值从0变到1说明是从后台切到前台
if (activityStartCount == 1) {
//从后台切到前台
mOnAppStatusListener?.onForeground()
}
}
override fun onActivityResumed(activity: Activity) {
APieLog.d(TAG, "onActivityResumed: $activity")
}
override fun onActivityPaused(activity: Activity) {
APieLog.d(TAG, "onActivityPaused: $activity")
}
override fun onActivityStopped(activity: Activity) {
APieLog.d(TAG, "onActivityStopped: $activity")
activityStartCount--
// 数值从1到0说明是从前台切到后台
if (activityStartCount == 0) {
// 从前台切到后台
mOnAppStatusListener?.onBackground()
}
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
APieLog.d(TAG, "onActivitySaveInstanceState: $activity")
}
override fun onActivityDestroyed(activity: Activity) {
APieLog.d(TAG, "onActivityDestroyed: $activity")
}
}
使用ForegroundCallbacks.kt
在项目的 application 里注册监听
class APieApplication : Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(ForegroundCallbacks(object : OnAppStatusListener {
override fun onForeground() {
APieLog.d("ForegroundCallbacks", "正在前台")
}
override fun onBackground() {
APieLog.d("ForegroundCallbacks", "进入后台")
}
}))
}
}
效果
方案二:使用 ProcessLifecycleOwner
ProcessLifecycleOwner是Google Lifecycle中的一个类,更优雅的监听前后台的切换
关于**ProcessLifecycleOwner,官方文字是这样介绍的**
使用方法
1、 引入依赖库
implementation "androidx.lifecycle:lifecycle-process:2.2.0"
2、代码中使用
class MainActivity : AppCompatActivity() {
private var binding: ActivityMainBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
runOnUiThread {
// 前后台监听
ProcessLifecycleOwner.get().lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
APieLog.d("ForegroundCallbacks-1", "onProcessLifecycleChanged: $event")
})
}
}
}
效果
源码解读
核心代码ProcessLifecycleOwner
根据上图得知 ProcessLifecycleOwner
实现了 LifecycleOwner
接口
由于在ProcessLifecycleOwnerInitializer
中初始化时传入了 Context,因此 ProcessLifecycleOwner
在 attach 方法中借助 Context 拿到了 Application 实例,并调用了 registerActivityLifecycleCallbacks
@Suppress("DEPRECATION")
internal fun attach(context: Context) {
handler = Handler()
registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
val app = context.applicationContext as Application
app.registerActivityLifecycleCallbacks(object : EmptyActivityLifecycleCallbacks() {
@RequiresApi(29)
override fun onActivityPreCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
// We need the ProcessLifecycleOwner to get ON_START and ON_RESUME precisely
// before the first activity gets its LifecycleOwner started/resumed.
// The activity's LifecycleOwner gets started/resumed via an activity registered
// callback added in onCreate(). By adding our own activity registered callback in
// onActivityPreCreated(), we get our callbacks first while still having the
// right relative order compared to the Activity's onStart()/onResume() callbacks.
Api29Impl.registerActivityLifecycleCallbacks(activity,
object : EmptyActivityLifecycleCallbacks() {
override fun onActivityPostStarted(activity: Activity) {
activityStarted()
}
override fun onActivityPostResumed(activity: Activity) {
activityResumed()
}
})
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
// Only use ReportFragment pre API 29 - after that, we can use the
// onActivityPostStarted and onActivityPostResumed callbacks registered in
// onActivityPreCreated()
if (Build.VERSION.SDK_INT < 29) {
activity.reportFragment.setProcessListener(initializationListener)
}
}
override fun onActivityPaused(activity: Activity) {
activityPaused()
}
override fun onActivityStopped(activity: Activity) {
activityStopped()
}
})
}
EmptyActivityLifecycleCallbacks
为 Application.ActivityLifecycleCallbacks
的实现类,内部为空实现
内部也维护了几个变量,用来记录 start 和 resume 的数量
private var startedCounter = 0
private var resumedCounter = 0
private var pauseSent = true
private var stopSent = true
在不同的时机调用
internal fun activityStarted() {
startedCounter++
if (startedCounter == 1 && stopSent) {
registry.handleLifecycleEvent(Lifecycle.Event.ON_START)
stopSent = false
}
}
internal fun activityResumed() {
resumedCounter++
if (resumedCounter == 1) {
if (pauseSent) {
registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
pauseSent = false
} else {
handler!!.removeCallbacks(delayedPauseRunnable)
}
}
}
internal fun activityPaused() {
resumedCounter--
if (resumedCounter == 0) {
handler!!.postDelayed(delayedPauseRunnable, TIMEOUT_MS)
}
}
internal fun activityStopped() {
startedCounter--
dispatchStopIfNeeded()
}
internal fun dispatchPauseIfNeeded() {
if (resumedCounter == 0) {
pauseSent = true
registry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
}
}
internal fun dispatchStopIfNeeded() {
if (startedCounter == 0 && pauseSent) {
registry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
stopSent = true
}
}
在 activityStarted 和 activityResumed 方法中对 这两个数值进行 ++,同时更新 lifecycle 状态
在 activityPaused 和 activityStopped 方法对这两个数值进行 --
并且在 activityPaused 时做了个 700ms 的延时
@VisibleForTesting
internal const val TIMEOUT_MS: Long = 700 // mls
internal fun activityPaused() {
resumedCounter--
if (resumedCounter == 0) {
handler!!.postDelayed(delayedPauseRunnable, TIMEOUT_MS)
}
}
这里为什么要延时呢?
在测试的时候发现一个很奇怪的问题:
当退出应用又立马切回来的时候,并不会调用onStop和onResume方法
反复试了好几遍,终于找到了原因:就是这里的延时,当切换的时间太短时,就监听不到了。
经过思考,发现:
我们先来看看这几个场景:在 A-Activity 中打开 B-Activity,生命周期是这样的:
A: onPause
B: onCreate
B: onStart
B: onResume
A: onStop
接着:关闭 B-Activity 返回 A-Activity
B: onPause
A: onRestart
A: onStart
A: onResume
B: onStop
B: onDestroy
再接着:从 App 返回桌面
A:onPause
A:onStop
ProcessLifecycleOwner 的原理其实是监听Activity的生命周期,当你在 App内部新开一个Activity或者销毁Activity时,都会引起Activity调用onPause,onStop方法。
所以,当ProcessLifecycleOwner接受到onPause,onStop这些事件时,并不知道是来自用户退到后台,还是来自app内部的Activity变化。
因此,这里才设置了一个延时,如果是app内部Activity变动,那么一个Activity的onPause必然会伴随另一个Activity的onResume。
从前面的流程可以看出:不管什么情况,都会先调用onPause
如果太长时间没有调用onResume,就认为是退到后台
如果很快onResume就被调用了,那就认为这只是app内部的activity在变化。这就是设置延时的作用。