Android Jitpack 組件之 Lifecycle(Kotlin)

一、導入 Library

在 build.gradle 中導入庫:

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0'

添加 Java 和 Kotlin 的 java8 支持:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
    jvmTarget = '1.8'
}

二、監聽 Activity 生命週期

監聽生命週期有兩種方式,一是繼承 DefaultLifecycleObserver,在其重載方法中處理。二是使用註解,在方法上添加生命週期回調事件的註解,就能接收到對應回調。
Google 官方推薦使用方式一,因爲隨着 Java8 的流行,註解可能會被廢棄。

方式一:繼承 DefaultLifecycleObserver

新建 MyLifecycleObserver 類,繼承自 DefaultLifecycleObserver

class MyLifecycleObserver : DefaultLifecycleObserver{
    override fun onCreate(owner: LifecycleOwner) {
        super.onCreate(owner)
        Log.d("~~~", "onCreate")
    }

    override fun onResume(owner: LifecycleOwner) {
        super.onResume(owner)
        Log.d("~~~", "onResume")
    }

    override fun onPause(owner: LifecycleOwner) {
        super.onPause(owner)
        Log.d("~~~", "onPause")
    }

    override fun onStart(owner: LifecycleOwner) {
        super.onStart(owner)
        Log.d("~~~", "onStart")
    }

    override fun onStop(owner: LifecycleOwner) {
        super.onStop(owner)
        Log.d("~~~", "onStop")
    }

    override fun onDestroy(owner: LifecycleOwner) {
        super.onDestroy(owner)
        Log.d("~~~", "onDestroy")
    }
}

在需要監聽生命週期的 Activity 中,給 lifecycle 添加此觀察者:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        lifecycle.addObserver(MyLifecycleObserver())
    }
}

大功告成,現在這個 activity 的生命週期回調觸發時,MyLifecycleObserver 的對應方法就能監聽到了。

方式二:使用註解

新建 MyLifecycleObserver 類,讓其繼承自 LifecycleObserver。通過給方法添加 OnLifecycleEvent 註解的方式監聽生命週期。

class MyLifecycleObserver : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun create() {
        Log.d("~~~", "ON_CREATE")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun start() {
        Log.d("~~~", "ON_START")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun resume() {
        Log.d("~~~", "ON_RESUME")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun pause() {
        Log.d("~~~", "ON_PAUSE")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stop() {
        Log.d("~~~", "ON_STOP")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy() {
        Log.d("~~~", "ON_DESTROY")
    }
}

在需要監聽生命週期的 Activity 中,給 lifecycle 添加此觀察者:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        lifecycle.addObserver(MyLifecycleObserver())
    }
}

兩種方式的效果是一樣的。

三、Lifecycle 的狀態

3.1.五種狀態

Lifecycle 一共有五種狀態,分別是:

  • INITIALIZED
  • CREATED
  • STARTED
  • RESUMED
  • DESTROYED

官網上用一張圖表示了 Lifecycle 的狀態與生命週期的關係:

3.2.狀態改變的時機

我們修改一下 MainActivity,來測一下 Lifecycle 的幾種狀態改變的時機。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        Log.d("~~~", "OnCreate start, ${lifecycle.currentState}")
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        lifecycle.addObserver(MyLifecycleObserver())
        Log.d("~~~", "OnCreate end, ${lifecycle.currentState}")
    }

    override fun onStart() {
        Log.d("~~~", "onStart start, ${lifecycle.currentState}")
        super.onStart()
        Log.d("~~~", "onStart end, ${lifecycle.currentState}")
    }

    override fun onResume() {
        Log.d("~~~", "onResume start, ${lifecycle.currentState}")
        super.onResume()
        Log.d("~~~", "onResume end, ${lifecycle.currentState}")
        Thread(Runnable {
            Thread.sleep(1000)
            Log.d("~~~", "waiting 1 second after onResume, ${lifecycle.currentState}")
        }).start()
    }

    override fun onPause() {
        Log.d("~~~", "onPause start, ${lifecycle.currentState}")
        super.onPause()
        Log.d("~~~", "onPause end, ${lifecycle.currentState}")
    }

    override fun onStop() {
        Log.d("~~~", "onStop start, ${lifecycle.currentState}")
        super.onStop()
        Log.d("~~~", "onStop end, ${lifecycle.currentState}")
    }

    override fun onDestroy() {
        Log.d("~~~", "onDestroy start, ${lifecycle.currentState}")
        super.onDestroy()
        Log.d("~~~", "onDestroy end, ${lifecycle.currentState}")
    }
}

運行程序,程序打開後,等待 1 秒多的時間(等待 1 秒是爲了便於觀察 RESUMED 狀態),點擊返回鍵退出。Log 輸出如下:

2020-03-03 22:29:39.569 20742-20742/com.example.myapplication D/~~~: OnCreate start, currentState is INITIALIZED
2020-03-03 22:29:39.747 20742-20742/com.example.myapplication D/~~~: OnCreate end, currentState is INITIALIZED
2020-03-03 22:29:39.750 20742-20742/com.example.myapplication D/~~~: ON_CREATE
2020-03-03 22:29:39.754 20742-20742/com.example.myapplication D/~~~: onStart start, currentState is CREATED
2020-03-03 22:29:39.758 20742-20742/com.example.myapplication D/~~~: onStart end, currentState is CREATED
2020-03-03 22:29:39.758 20742-20742/com.example.myapplication D/~~~: ON_START
2020-03-03 22:29:39.759 20742-20742/com.example.myapplication D/~~~: onResume start, currentState is STARTED
2020-03-03 22:29:39.759 20742-20742/com.example.myapplication D/~~~: onResume end, currentState is STARTED
2020-03-03 22:29:39.760 20742-20742/com.example.myapplication D/~~~: ON_RESUME
2020-03-03 22:29:40.761 20742-20794/com.example.myapplication D/~~~: waiting 1 second after onResume, currentState is RESUMED
2020-03-03 22:29:48.028 20742-20742/com.example.myapplication D/~~~: ON_PAUSE
2020-03-03 22:29:48.028 20742-20742/com.example.myapplication D/~~~: onPause start, currentState is STARTED
2020-03-03 22:29:48.029 20742-20742/com.example.myapplication D/~~~: onPause end, currentState is STARTED
2020-03-03 22:29:48.655 20742-20742/com.example.myapplication D/~~~: ON_STOP
2020-03-03 22:29:48.655 20742-20742/com.example.myapplication D/~~~: onStop start, currentState is CREATED
2020-03-03 22:29:48.656 20742-20742/com.example.myapplication D/~~~: onStop end, currentState is CREATED
2020-03-03 22:29:48.660 20742-20742/com.example.myapplication D/~~~: ON_DESTROY
2020-03-03 22:29:48.660 20742-20742/com.example.myapplication D/~~~: onDestroy start, currentState is DESTROYED
2020-03-03 22:29:48.661 20742-20742/com.example.myapplication D/~~~: onDestroy end, currentState is DESTROYED

經過測試,我們發現打開 app 時:

  • Lifecycle 在 Activity 的 onCreate 方法中,狀態一直是 INITIALIZED。Activity 的 onCreate 執行完後,纔會回調 Observer 的 onCreate 方法,然後狀態變成 CREATED
  • Lifecycle 在 Activity 的 onStart 方法中,狀態一直是 CREATED。Activity 的 onStart 執行完後,纔會回調 Observer 的 onStart 方法,然後狀態變成 STARTED
  • Lifecycle 在 Activity 的 onResume 方法中,狀態一直是 STARTED。Activity 的 onResume 執行完後,纔會回調 Observer 的 onResume 方法,然後狀態變成 RESUMED

關閉 app 時:

  • Activity 的 onPause 執行前,先回調 Lifecycle 的 onPause 方法,Lifecycle 狀態變爲 STARTED。然後再去執行 Activity 的 onPause 方法,在 Activity 的 onPause 方法中,Lifecycle 的狀態一直是 STARTED
  • Activity 的 onStop 執行前,先回調 Lifecycle 的 onStop 方法,Lifecycle 狀態變爲 CREATED。然後再去執行 Activity 的 onStop 方法,在 Activity 的 onStop 方法中,Lifecycle 的狀態一直是 CREATED
  • Activity 的 onDestroy 執行前,先回調 Lifecycle 的 onDestroy 方法,Lifecycle 狀態變爲 DESTROYED。然後再去執行 Activity 的 onDestroy 方法,在 Activity 的 onDestroy 方法中,Lifecycle 的狀態一直是 DESTROYED

總結起來就是:進入時最後改 Lifecycle 狀態,退出時最先改 Lifecycle 狀態。

3.3.active 與 inactive 的 Lifecycle

當 Lifecycle 處於 STARTED 或 RESUMED 狀態時,我們認爲 Lifecycle 是 active 的,否則認爲是 inactive 的。

四、監聽 Application 生命週期

監聽整個 app 的生命週期,官方文檔推薦使用 ProcessLifecycleOwner。
同樣可以使用繼承或註解兩種方式。MyLifecycleObserver 類和上述代碼一模一樣。在 Application 中,使用 ProcessLifecycleOwner 添加此觀察者:

class MyApplication : Application(), LifecycleObserver {
    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(MyLifecycleObserver())
    }
}

當 app 啓動時,依次回調 onCreate、onStart、onResume,當 app 退出時,依次回調 onPause、onStop,並且永遠不會回調 onDestroy。官方文檔中提到,onPause、onStop 回調是有一定間隔的,目的是保證在手機旋轉等配置改變時引起的 Activity 銷燬和重建時不發送 Event。查看源碼可以發現,這個間隔時間是 700ms。並且源碼中是通過監聽前臺 Activity 的數量實現的此功能。我們也可以通過這種方式來監聽 app 前後臺切換。

注:筆者在 mac 的安卓模擬器上使用 ProcessLifecycleOwner 沒有監聽到 onPause、onStop 回調,但 Windows 的模擬器上可以監聽到,暫不清楚原因。

五、監聽 app 前後臺切換

新建 MyActivityLifecycleCallbacks 單例:

object MyActivityLifecycleCallbacks : Application.ActivityLifecycleCallbacks {
    private var foregroundActivityCounts = 0

    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
    }

    override fun onActivityStarted(activity: Activity) {
        if (foregroundActivityCounts++ == 0) {
            Log.d("~~~", "foreground")
        }
    }

    override fun onActivityResumed(activity: Activity) {
    }

    override fun onActivityPaused(activity: Activity) {
    }

    override fun onActivityStopped(activity: Activity) {
        if (--foregroundActivityCounts == 0) {
            Log.d("~~~", "background")
        }
    }

    override fun onActivityDestroyed(activity: Activity) {
    }

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
    }

    fun isAppForeground(): Boolean {
        return foregroundActivityCounts > 0
    }

}

在 Application 中註冊此 LifecycleCallbacks

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        registerActivityLifecycleCallbacks(MyActivityLifecycleCallbacks)
    }
}

在 MyActivityLifecycleCallbacks 中,我們維護了一個 int 變量 foregroundActivityCounts ,用來記錄此 app 前臺 Activity 的數量。
每當 Activity 的 onStart 回調時,foregroundActivityCounts++,每當 Activity 的 onStop 回調時,–foregroundActivityCounts。

如果 foregroundActivityCounts 從 0 變成 1,說明 app 進入前臺,如果 foregroundActivityCounts 從 1 變成 0,說明 app 進入後臺。

MyActivityLifecycleCallbacks 聲明瞭 isAppForeground 方法,通過 foregroundActivityCounts 是否大於 0 來判斷 app 是否在前臺。

六、總結

在應用開發中,我們常常會有一些邏輯需要與生命週期綁定。比如:頁面展示在前臺時播放視頻,切換到後臺時暫停播放。應用開始時初始化,應用退出時釋放資源。通過本文介紹的這些監聽方法,可以讓這些代碼邏輯自己處理生命週期,實現更好的解耦。

僞代碼表示如下,使用 Lifecycle 前:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        LibraryA.init()
        LibraryB.init()
        LibraryC.init()
    }

    override fun onResume() {
        super.onResume()
        LibraryA.resume()
        LibraryB.resume()
        LibraryC.resume()
    }

    override fun onPause() {
        super.onPause()
        LibraryA.pause()
        LibraryB.pause()
        LibraryC.pause()
    }

    override fun onDestroy() {
        super.onDestroy()
        LibraryA.release()
        LibraryB.release()
        LibraryC.release()
    }
}

使用 Lifecycle 後:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        lifecycle.addObserver(LifecycleObserverA())
        lifecycle.addObserver(LifecycleObserverB())
        lifecycle.addObserver(LifecycleObserverC())
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章