Lifecycle(生命周期) 在任何 GUI 编程中都是基石般的存在,Android 也不例外。

作为用户,在页面跳转,旋转屏幕,查看通知,切换应用等日常操作中,都期望获得流畅连贯的使用体验。在这背后,就需要我们开发者在生命周期组件的不同阶段中进行相应的逻辑处理。这里的生命周期组件,可能是整个应用,也可能是单个页面。对应到 Android 中,Activity、Fragment,甚至 Service 都可以成为生命周期组件。

现在假设这样一个需求,你需要封装一个播放器的基础组件,供各个部门调用。最基本的流程就是打开 Activity,初始化资源并播放,退出 Activity,停止播放。

不假思索直接下笔,就很容易诞生下面这样的 “屎山代码” 。

class ShitAVPlayer {
   fun init() {}
    fun start() {}
    fun stop() {}
}

调用方需要在 Activity/Fragment 等生命周期组件的不同生命周期回调中,调用相应的方法。

class VideoActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
       shitAVPlayer.init()
        shitAVPlayer.start()
    }

    override fun onStop() {
        super.onStop()
        shitAVPlayer.stop()
    }
}

功能实现上没有太大问题,但下面几个场景难免会给别人一种在屎山翻屎的感觉。

  1. 你的 ShitAVPlayer 作为基础组件提供给其他部门使用,当量级达到一定程度时,你没有办法保证每一个调用方都能合理且正确的处理生命周期,满地跑的内存泄漏一定少不了你的锅。

— 什么?你自己没调用,还赖我?

— 鬼知道我一个生命周期回调中要处理多少逻辑?你的 ShitAVPlayer 人如其名!

  1. 如果你的 ShitAVPlayer 需要在 onCreate() 中进行初始化,并提供了一个异步回调告知初始化状态,以判断是否可以开启。那么你可能无法保证执行回调时,生命周期组件是否已经 onStop(),这又得依靠调用方自行处理。这就可能造成不符合预期的生命周期情况。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        shitAVPlayer.init { success ->
            // 是否还有必要开启
            if (success) shitAVPlayer.start()
        }
    }
    
    
  2. 如果产品给你加了这么一个需求,播放时按 Home 键回到桌面要暂停播放,返回时再恢复播放。你三下五除二给 ShitAVPlayer 加了onResume() 和 onPause() 方法,然后花费大量时间和各个调用方同步。

    — 老哥,有空在你的 Activity 的 onResume 和 onPause 回调加个方法呗,😜

    — 加你个 xx !

本着是人就会犯错的原则,一个优秀基础组件的基本修养就是 能不麻烦别人的事情就尽量自己做 。

要想把 ShitAVPlayer 变成 ExcellentAVPlayer ,就得 赋予组件感知外部生命周期的能力

基于观察者模式的 Lifecycle

梳理一下需求,我们需要让 ShitAVPlayer 能够 自动感知外部生命周期组件的生命周期事件或者回调。这里存在三个角色:

  1. 生命周期组件,不妨叫做 LifecycleOwner 。Activity/Fragment/Service 等等任何具有生命周期的组件,都可以当作 LifecycleOwner 。
  2. 生命周期观察者,不妨叫做 LifecycleObserver 。ShitAVPlayer 这一类的需要感知生命周期的对象。
  3. 生命周期 本体。在面向对象的世界里,不可避免的需要一个 Lifecycle 类来表示生命周期。

很显然,这是一个典型的观察者模式,LifecycleObserver 观察 LifecycleOwner 的生命周期变化。