在开发过程中,你肯定遇到过需要监听 activity/Fragment 生命周期的问题。解决的思路也很简单,就是创建一个回调接口,然后在 activity/Fragment 中注册监听,当生命周期变化时遍历通知注册的类就可以了。如下图所示:
Lifecycle 是什么
Google也注意到了这个问题,就提出了 Lifecycle 来解决这个问题。Lifecycle 是 Jetpack 架构组件中用来感知生命周期的组件,使用 Lifecycle 可以帮助开发者写出与生命周期相关且更简洁、更易维护的代码。使用 Lifecycle 组件,我们就不需要再写监听生命周期的重复代码,也能避免编写过程中代码出错。
第一步先添加依赖
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.lifecycle:lifecycle-service:2.7.0") //可选 service Lifecycle 依赖
implementation("androidx.lifecycle:lifecycle-process:2.7.0") //可选 application Lifecycle 依赖
使用 Lifecycle 组件也很简单,我们只需要实现 LifecycleObserver 接口,实现对应的方法,然后在activity/Fragment中注册监听就可以了。代码如下:
class TestLifecycleClassA: DefaultLifecycleObserver {
//监听对应的生命周期的调用
override fun onResume(owner: LifecycleOwner) {
}
}
class TestLifecycleClassB: LifecycleEventObserver {
//监听对应的生命周期的切换
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
}
}
//在activity/Fragment中注册
lifecycle.addObserver(TestLifecycleClassA())
lifecycle.addObserver(TestLifecycleClassB())
LifecycleObserver 有两个实现的子接口,分别是 DefaultLifecycleObserver 、LifecycleEventObserver。(之前的版本还有FullLifecycleObserver,后面被移除了)。
DefaultLifecycleObserver 用来监听生命周期的调用;而 LifecycleEventObserver 用来监听生命周期的切换。
Lifecycle 的原理
看到这里,你可能会问:为什么我们只要注册了 Lifecycle ,就可以监听到生命周期的变化呢?原理其实很简单,就是最常见的方案,如下图所示:
可以看出,生命周期变更的通知是 LifeCycleOwner 和 LifecycleRegistry 实现的。那 LifeCycleOwner 和 LifecycleRegistry 又是什么呢?
如上图所示,其实很简单,LifeCycleOwner 表示的是需要监听生命周期的宿主,其内部包含的 lifecycle 变量才是真正分发生命周期的类,其实现类是 LifecycleRegistry 。 Fragment、ComponentActivity 默认都已经实现了 LifeCycleOwner,所以我们可以直接通过 lifecycle.addObserver 来注册监听。
public interface LifecycleOwner {
/**
* Returns the Lifecycle of the provider.
*
* @return The lifecycle of the provider.
*/
public val lifecycle: Lifecycle
}
当生命周期触发或者变更时,宿主的生命周期事件会分发到 LifecycleRegistry 中,通过 LifecycleRegistry 来通知所有注册的监听。
Lifecycle 的状态和事件
Lifecycle 的状态有五种,它们被定义在 State 枚举中,我们可以通过 lifecycle.currentState 来获取当前的状态。在实际应用用,会比较生命周期状态的大小,来决定是否执行对应方法。比如,当状态比 STARTED 时取消任务,这时任务在 STARTED、RESUMED 状态中可以执行,而在 DESTROYED、INITIALIZED、CREATED 会被取消。
//最小的是 DESTROYED,最大的是 RESUMED
public enum State {
DESTROYED,
INITIALIZED,
CREATED,
STARTED,
RESUMED;
}
而 Lifecycle 的事件有七种,它们被定义在 Event 中。我们可以使用 @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) 注解的方式来监听事件的转换,但是现在不推荐这种方法。而是建议使用 LifecycleEventObserver 来监听。
public enum Event {
ON_CREATE,
ON_START,
ON_RESUME,
ON_PAUSE,
ON_STOP,
ON_DESTROY,
ON_ANY; //匹配任何事件,可用于注解
}
Lifecycle 的状态和事件的关系如下图所示:
Lifecycle 和 Service
如果需要监听 Service 的生命周期,需要使用 LifecycleService 。代码示例如下:
//继承 LifecycleService 来处理 Service 的生命周期
class MyService: LifecycleService() {
init {
//直接通过 lifecycle 监听生命周期
lifecycle.addObserver(TestLifecycleClass())
}
}
Lifecycle 和 Application
当我们想知道应用程序当前处在前台还是后台,或者当应用程序从后台回到前台时,我们也可以使用 Lifecycle 组件中的 ProcessLifecycleOwner 来实现。代码如下所示:
ProcessLifecycleOwner.get().lifecycle.addObserver(object: LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
when (event) {
Lifecycle.Event.ON_START -> {} //回到前台
Lifecycle.Event.ON_STOP -> {} //退到后台
else -> {}
}
}
})
ProcessLifecycleOwner 中,Lifecycle.Event 对应的事件如下:
- Lifecycle.Event.ON_CREATE: 在应用进程启动时分发,只会分发一次;
- Lifecycle.Event.ON_START:在应用进程进入前台(STARTED)时分发,可能分发多次;
- Lifecycle.Event.ON_RESUME:在应用进程进入前台(RESUMED)时分发,可能分发多次;
- Lifecycle.Event.ON_PAUSE:在应用退出前台(PAUSED)时分发,可能分发多次;
- Lifecycle.Event.ON_STOP:在应用退出前台(STOPPED)时分发,可能分发多次;
- Lifecycle.EVENT.ON_DESTROY:注意,不会被分发
Lifecycle KTX
Lifecycle KTX 是 Google 提供的一种在指定的生命周期更方便地执行代码的方式。通过它的 API,我们就可以通过简单的方式来实现复杂的操作。
findViewTreeLifecycleOwner
我们知道,如果需要注册生命周期监听,需要在生命周期宿主中通过 lifecycle.addObserver 来实现。但是,获取宿主也很麻烦,需要先通过 context is Fragment/Activity 来判断获取。为了解决这个问题,Google 提供了findViewTreeLifecycleOwner 的扩展方法,我们只需要通过 View 就可以获取其对应的 LifecycleOwner。
代码如下:
view.findViewTreeLifecycleOwner()?.lifecycle?.addObserver(TestLifecycleClass())
lifecycleScope
lifecycleScope 是 Lifecycle KTX 提供的监听 Lifecycle 的协程 Scope,通过 lifecycleScope 启动的协程会在生命周期进入 DESTROY 时取消通过它启动的协程任务。
//启动一个协程
lifecycleScope.launch {
}
launchWhenStarted、withStarted、repeatOnLifecycle
上图是launchWhenStarted 和 repeatOnLifecycle 比较优势图,图片来源launchWhenX 给我弃用了,这可咋整。可以看到:
- launchWhenStarted 可以指定在
onStart的生命周期执行协程协程代码,并在生命周期状态低于指定状态时挂起就会挂起协程。类似的方法还有 launchWhenCreated、launchWhenResumed。 - repeatOnLifecycle(Lifecycle.State.STARTED) 则会在指定
onStart的生命周期执行协程协程代码,生命周期状态低于指定状态时就会取消协程的执行。然后在onStart时重新开始执行。 - withStarted 与 launchWhenStarted 类似,区别是 withStarted 需要在
lifecycleScope.launch中使用,其执行代码块不能使用挂起函数。
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
//可以使用挂起函数
delay(1000)
}
lifecycle.withStarted {
//不可以使用挂起函数
}
}
lifecycleScope.launchWhenStarted {
//可以使用挂起函数
delay(1000)
}
需要注意launchWhenStarted及其类似的API已经被废弃,具体废弃原因可以看使用更为安全的方式收集 Android UI 数据流