5-處理生命週期

處理生命週期

androidx.lifecycle 軟件包提供了可用於構建生命週期感知型組件的類和接口 - 這些組件可以根據 Activity 或 Fragment 的當前生命週期狀態自動調整其行爲。

    dependencies {
        def lifecycle_version = "2.2.0"
        def arch_version = "2.1.0"

        // ViewModel
        implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
        // LiveData
        implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
        // Lifecycles only (without ViewModel or LiveData)
        implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"

        // Saved state module for ViewModel
        implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"

        // Annotation processor
        kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
        // alternately - if using Java8, use the following instead of lifecycle-compiler
        implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

        // optional - ReactiveStreams support for LiveData
        implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"

        // optional - Test helpers for LiveData
        testImplementation "androidx.arch.core:core-testing:$arch_version"
    }

示例:

    internal class MyLocationListener(
            private val context: Context,
            private val callback: (Location) -> Unit
    ) {

        fun start() {
            // connect to system location service
        }

        fun stop() {
            // disconnect from system location service
        }
    }

    class MyActivity : AppCompatActivity() {
        private lateinit var myLocationListener: MyLocationListener

        override fun onCreate(...) {
            myLocationListener = MyLocationListener(this) { location ->
                // update UI
            }
        }

        public override fun onStart() {
            super.onStart()
            myLocationListener.start()
            // manage other components that need to respond
            // to the activity lifecycle
        }

        public override fun onStop() {
            super.onStop()
            myLocationListener.stop()
            // manage other components that need to respond
            // to the activity lifecycle
        }
    }
    

雖然此示例看起來沒問題,但在真實的應用中,最終會有太多管理界面和其他組件的調用,以響應生命週期的當前狀態。管理多個組件會在生命週期方法(如 onStart()onStop())中放置大量的代碼,這使得它們難以維護。

此外,無法保證組件會在 Activity 或 Fragment 停止之前啓動。在我們需要執行長時間運行的操作(如 onStart() 中的某種配置檢查)時尤其如此。這可能會導致出現一種競爭條件,在這種條件下,onStop() 方法會在 onStart() 之前結束,這使得組件留存的時間比所需的時間要長。

androidx.lifecycle 軟件包提供的類和接口可幫助您以彈性和隔離的方式解決這些問題。

生命週期

Lifecycle 是一個類,用於存儲有關組件(如 Activity 或 Fragment)的生命週期狀態的信息,並允許其他對象觀察此狀態。

Lifecycle 使用兩種主要枚舉跟蹤其關聯組件的生命週期狀態:

  • 事件

    從框架和 Lifecycle 類分派的生命週期事件。這些事件映射到 Activity 和 Fragment 中的回調事件。

  • 狀態

    Lifecycle 對象跟蹤的組件的當前狀態。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JcoqOlsR-1592584470619)(/Users/liubo/Desktop/筆記/Jetpack/lifecycle-states.svg)]

圖 1. 構成 Android Activity 生命週期的狀態和事件

類可以通過向其方法添加註解來監控組件的生命週期狀態。然後,您可以通過調用 Lifecycle 類的 addObserver() 方法並傳遞觀察者的實例來添加觀察者,如以下示例中所示:

    class MyObserver : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        fun connectListener() {
            ...
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        fun disconnectListener() {
            ...
        }
    }

    myLifecycleOwner.getLifecycle().addObserver(MyObserver())
    

在上面的示例中,myLifecycleOwner 對象實現了 LifecycleOwner 接口,我們將在接下來的部分中對該接口進行說明。

LifecycleOwner

LifecycleOwner 是單一方法接口,表示類具有 Lifecycle。它具有一種方法(即 getLifecycle()),該方法必須由類實現。如果您嘗試管理整個應用進程的生命週期,請參閱 ProcessLifecycleOwner

實現 LifecycleObserver 的組件可與實現 LifecycleOwner 的組件無縫協同工作,因爲所有者可以提供生命週期,而觀察者可以註冊以觀察生命週期。

對於位置跟蹤示例,我們可以讓 MyLocationListener 類實現 LifecycleObserver,然後在 onCreate() 方法中使用 Activity 的 Lifecycle 對其進行初始化。這樣,MyLocationListener 類便可以“自給自足”,這意味着,對生命週期狀態的變化做出響應的邏輯會在 MyLocationListener(而不是在 Activity)中進行聲明。讓各個組件存儲自己的邏輯,可使 Activity 和 Fragment 邏輯更易於管理。

    class MyActivity : AppCompatActivity() {
        private lateinit var myLocationListener: MyLocationListener

        override fun onCreate(...) {
            myLocationListener = MyLocationListener(this, lifecycle) { location ->
                // update UI
            }
            Util.checkUserStatus { result ->
                if (result) {
                    myLocationListener.enable()
                }
            }
        }
    }
    

一個常見的用例是,如果 Lifecycle 現在未處於良好的狀態,則應避免調用某些回調。例如,如果回調在 Activity 狀態保存後運行 Fragment 事務,就會引發崩潰,因此我們絕不能調用該回調。

爲簡化此用例,Lifecycle 類允許其他對象查詢當前狀態。

    internal class MyLocationListener(
            private val context: Context,
            private val lifecycle: Lifecycle,
            private val callback: (Location) -> Unit
    ) {

        private var enabled = false

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun start() {
            if (enabled) {
                // connect
            }
        }

        fun enable() {
            enabled = true
            if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
                // connect if not connected
            }
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun stop() {
            // disconnect if connected
        }
    }
    

對於此實現,LocationListener 類可以完全感知生命週期。如果我們需要從另一個 Activity 或 Fragment 使用 LocationListener,只需對其進行初始化。所有設置和拆解操作都由類本身管理。

實現自定義LifecycleOwner

Support Library 26.1.0 及更高版本中的 Fragment 和 Activity 已實現 LifecycleOwner 接口。

如果您有一個自定義類並希望使其成爲 LifecycleOwner,您可以使用 LifecycleRegistry 類,但需要將事件轉發到該類,如以下代碼示例中所示:

    class MyActivity : Activity(), LifecycleOwner {

        private lateinit var lifecycleRegistry: LifecycleRegistry

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            lifecycleRegistry = LifecycleRegistry(this)
            lifecycleRegistry.markState(Lifecycle.State.CREATED)
        }

        public override fun onStart() {
            super.onStart()
            lifecycleRegistry.markState(Lifecycle.State.STARTED)
        }

        override fun getLifecycle(): Lifecycle {
            return lifecycleRegistry
        }
    }
    

生命週期感知型組件的最佳做法

  • 使界面控制器(Activity 和 Fragment)儘可能保持精簡。它們不應試圖獲取自己的數據,而應使用 ViewModel 執行此操作,並觀察 LiveData 對象以將更改體現到視圖中。
  • 設法編寫數據驅動型界面,對於此類界面,界面控制器的責任是隨着數據更改而更新視圖,或者將用戶操作通知給 ViewModel
  • 將數據邏輯放在 ViewModel 類中。 ViewModel 應充當界面控制器與應用其餘部分之間的連接器。不過要注意,ViewModel 不負責獲取數據(例如,從網絡獲取)。ViewModel 應調用相應的組件來獲取數據,然後將結果提供給界面控制器。
  • 使用 Data Binding 在視圖與界面控制器之間維持乾淨的接口。這樣一來,您可以使視圖更具聲明性,並儘量減少需要在 Activity 和 Fragment 中編寫的更新代碼。如果您更願意使用 Java 編程語言執行此操作,請使用諸如 Butter Knife 之類的庫,以避免樣板代碼並實現更好的抽象化。
  • 如果界面很複雜,不妨考慮創建 presenter 類來處理界面的修改。這可能是一項艱鉅的任務,但這樣做可使界面組件更易於測試。
  • 避免在 ViewModel 中引用 ViewActivity 上下文。 如果 ViewModel 存在的時間比 Activity 更長(在配置更改的情況下),Activity 將泄露並且不會由垃圾回收器妥善處置。
  • 使用 Kotlin 協程管理長時間運行的任務和其他可以異步運行的操作。

生命週期感知型組件的用例

生命週期感知型組件可使您在各種情況下更輕鬆地管理生命週期。下面列舉幾個例子:

  • 在粗粒度和細粒度位置更新之間切換。使用生命週期感知型組件可在位置應用可見時啓用細粒度位置更新,並在應用位於後臺時切換到粗粒度更新。藉助生命週期感知型組件 LiveData,應用可以在用戶使用位置發生變化時自動更新界面。
  • 停止和開始視頻緩衝。使用生命週期感知型組件可儘快開始視頻緩衝,但會推遲播放,直到應用完全啓動。此外,應用銷燬後,您還可以使用生命週期感知型組件終止緩衝。
  • 開始和停止網絡連接。藉助生命週期感知型組件,可在應用位於前臺時啓用網絡數據的實時更新(流式傳輸),並在應用進入後臺時自動暫停。
  • 暫停和恢復動畫可繪製資源。藉助生命週期感知型組件,可在應用位於後臺時暫停動畫可繪製資源,並在應用位於前臺後恢復可繪製資源。

處理ON_STOP事件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章