片段生命週期

每個 Fragment 執行個體都有專屬的生命週期。當使用者瀏覽並與應用程式互動時,片段會在新增、移除和進入或離開螢幕時,在生命週期中歷經各種狀態。

為了管理生命週期,Fragment 會導入 LifecycleOwner,開放一個 Lifecycle 物件,讓您透過 getLifecycle() 方法進行存取。

每個可能的 Lifecycle 狀態都會顯示在 Lifecycle.State 列舉中。

Lifecycle 上建構 Fragment,即可運用「利用生命週期感知元件處理生命週期」一文中提及的相關技術與類別。舉例來說,您可以使用生命週期感知元件在螢幕上顯示裝置的位置。此元件會在片段啟用時開始自動監聽,並在片段變成閒置狀態時停止監聽。

除了使用 LifecycleObserver 以外,Fragment 類別還具有可因應片段生命週期中各項變更的回呼方法。包括 onCreate()onStart()onResume()onPause()onStop()onDestroy()

片段檢視畫面具有獨立的 Lifecycle,且與片段的 Lifecycle 分別管理。片段則會保留 LifecycleOwner 的檢視畫面,可以透過 getViewLifecycleOwner()getViewLifecycleOwnerLiveData() 進行存取。有時候,生命週期感知元件只能在片段檢視畫面存在的情況下執行 (例如觀察只能顯示在畫面上的 LiveData)。在這類情況下,如果能取得檢視畫面的 Lifecycle 存取權限,就會很有幫助。

本主題會詳細說明 Fragment 的生命週期,解釋決定片段生命週期狀態的一些規則,以及 Lifecycle 狀態與片段生命週期回呼之間的關係。

片段與片段管理員

將片段執行個體化時,會以 INITIALIZED 狀態開始。您必須在 FragmentManager 中新增片段,才能在片段的剩餘生命週期中完成轉換。FragmentManager 負責判斷片段應處於哪個狀態,然後將其改變為該狀態。

除了片段的生命週期以外,FragmentManager 也會將片段附加到其代管活動上,並在片段停止使用時,將該片段從其上卸離。Fragment 類別有兩個回呼方法:onAttach()onDetach(),您可以在發生上述任一事件時覆寫以執行作業。

將片段新增至 FragmentManager 並附加至其代管活動時,系統會叫用 onAttach() 回呼。此時,片段處於啟用狀態,FragmentManager 會管理其生命週期狀態。這時,findFragmentById()FragmentManager 方法會傳回這個片段。

在任何生命週期狀態變更之前,系統都會呼叫 onAttach()

將片段從 FragmentManager 中移除並且從其代管活動上卸離時,系統會叫用 onDetach() 回呼。該片段將會停用,無法再使用 findFragmentById() 擷取。

在任何生命週期狀態變更之後,系統都會呼叫 onDetach()

請注意,這些回呼與 FragmentTransaction 方法 attach()detach() 無關。若要進一步瞭解這些方法,請參閱片段交易一文。

片段生命週期狀態及回呼

在判斷片段的生命週期狀態時,FragmentManager 會考量下列事項:

  • 片段的最大狀態取決於 FragmentManager。片段不能超過其 FragmentManager 狀態的進度。
  • 作為 FragmentTransaction 的一部分,可以使用 setMaxLifecycle() 設定片段最高的生命週期狀態。
  • 片段的生命週期狀態不得大於其父項。例如,父項片段或活動必須在其子項片段之前開始。同樣地,子項片段必須在父項片段或活動之前停止。
片段生命週期狀態及片段的生命週期回呼與片段的檢視畫面生命週期之間的關係
圖 1. 片段 Lifecycle 狀態及其在片段的生命週期回呼和片段的檢視畫面 Lifecycle 之間的關係。

圖 1 顯示了每個片段的 Lifecycle 狀態,以及這些片段與片段的生命週期回呼和片段的檢視畫面 Lifecycle 之間的關係。

一個片段會在生命週期中不斷演進,因此狀態會往上或向下移動。例如,新增至返回堆疊頂端的片段會從 CREATED 上移至 STARTED 再到 RESUMED。反之,如果片段從返回堆疊中移除,就會從狀態中向下移動,從 RESUMEDSTARTEDCREATED 並最後到 DESTROYED

向上狀態轉換

在生命週期狀態中往上移動時,片段會先為新狀態呼叫相關的生命週期回呼。完成這個回呼後,相關的 Lifecycle.Event 就會透過片段的 Lifecycle 傳送至觀察者,如果完成執行個體化,會接著依序顯示片段的檢視畫面 Lifecycle

已建立的片段

片段達到 CREATED 狀態後,就會新增至 FragmentManager,並且呼叫了 onAttach() 方法。

這裡適合透過片段 SavedStateRegistry 還原所有與片段本身相關的儲存狀態。請注意,目前系統尚未建立片段的檢視畫面,與片段檢視畫面相關的所有狀態只能在建立檢視畫面後還原。

此轉換作業會叫用 onCreate() 回呼。回呼也會收到一個 savedInstanceState Bundle 引數,其中包含之前由 onSaveInstanceState() 儲存的任何狀態。請注意,savedInstanceState 會在第一次建立片段時提供 null 值,但即使您並未覆寫 onSaveInstanceState(),對後續的重新建立來說也絕不會是空值。詳情請參閱以片段儲存狀態一節。

已建立的片段及初始化的檢視畫面

只有在 Fragment 提供有效的 View 執行個體時,系統才會建立片段的檢視畫面 Lifecycle。在多數情況下,您可以使用接收 @LayoutId片段建構函式,讓系統在適當的時間自動加載檢視畫面。您也可以將 onCreateView() 覆寫,透過程式輔助加載或建立片段的檢視畫面。

只有在片段的檢視畫面以非空值 View 執行個體化時,該 View 才能設定在片段上,可以使用 getView() 擷取。接著,getViewLifecycleOwnerLiveData() 會更新為最新的 INITIALIZED LifecycleOwner,以對應片段的檢視畫面。此時也會呼叫 onViewCreated() 生命週期回呼。

這也是適合用來設定檢視畫面初始狀態的地方,您可開始觀察 LiveData 執行個體,其回呼會更新片段的檢視畫面,並在片段的檢視畫面中對任何 RecyclerViewViewPager2 的執行個體設定配接器。

已建立的片段及檢視畫面

建立片段的檢視畫面後,若有先前的檢視畫面,系統就會將其狀態還原,該檢視畫面的 Lifecycle 則改為 CREATED 狀態。檢視畫面生命週期的擁有者也會將 ON_CREATE 事件發送給其觀察者。在這裡,您應該還原任何其他與片段檢視畫面有關的狀態。

此轉換作業也會叫用 onViewStateRestored() 回呼。

已開始的片段及檢視畫面

強烈建議您將生命週期感知元件連結到片段的 STARTED 狀態,因為此狀態可以確保片段的檢視畫面可以使用(如果已產生),而且能夠在片段的子項 FragmentManager 上安全執行 FragmentTransaction。如果片段的檢視畫面不是空值,則在片段的 Lifecycle 移至 STARTED 後,片段檢視畫面的 Lifecycle 就會立即移至 STARTED

片段變成 STARTED 時,就會叫用 onStart() 回呼。

重新啟用的片段及檢視畫面

片段顯示時,所有 AnimatorTransition 效果皆已完成,該片段已可供使用者使用。片段的 Lifecycle 會更改為 RESUMED 狀態,並叫用 onResume() 回呼。

轉換至 RESUMED 是一個適當的訊號,表示使用者現在可以與片段互動。非 RESUMED 的片段就不應手動將焦點設定於自己的檢視畫面,或是嘗試處理輸入方法的顯示

向下狀態轉換

當片段往下移至較低的生命週期狀態時,如果發生執行個體化現象,片段的檢視畫面 Lifecycle 會將相關的 Lifecycle.Event 發送給觀察者,接著才是片段的 Lifecycle。片段的生命週期事件發送後,該片段會呼叫相關的生命週期回呼。

已開始的片段及檢視畫面

使用者開始離開片段時,而片段仍持續顯示,則片段及其檢視畫面的 Lifecycle 會回到 STARTED 狀態,並傳送 ON_PAUSE 事件給其觀察者。片段接著會叫用其 onPause() 回呼。

已建立的片段及檢視畫面

片段停止顯示後,片段及其檢視畫面的 Lifecycle 就會進入 CREATED 狀態,並發送 ON_STOP 活動給其觀察者。此狀態轉換不僅會因為父項活動或片段停止而觸發,也會在父項活動或片段儲存狀態時觸發。這個動作可確保在儲存片段狀態之前就叫用 ON_STOP 事件。這使得 ON_STOP 事件會是最後安全地為子項 FragmentManager 執行 FragmentTransaction的時間點。

如圖 2 所示,onStop() 回呼的順序和以 onSaveInstanceState() 儲存狀態會因 API 層級而異。針對 API 級別 28 之前的所有 API 級別,onSaveInstanceState() 會在 onStop() 之前叫用。針對 API 級別 28 以上的 API 級別,呼叫順序則相反。

onStop() 和 onSaveInstanceState() 的呼叫順序差異
圖 2。onStop()onSaveInstanceState() 的呼叫順序差異。

建立的片段及刪除的檢視畫面

完成所有離開的動畫及轉換後,片段檢視畫面會從視窗卸離,片段的檢視畫面 Lifecycle 就會移至 DESTROYED 狀態,並將 ON_DESTROY 事件發送給觀察者。片段接著會叫用其 onDestroyView() 回呼。此時,片段的檢視畫面已到達生命週期尾端,getViewLifecycleOwnerLiveData() 會傳回 null 值。

此時,應該移除片段檢視畫面的所有參照,讓片段的檢視畫面能夠成為無用項目收集。

刪除的片段

如果片段遭移除,或是 FragmentManager 被刪除,則片段的 Lifecycle 就會移至 DESTROYED 狀態,並將 ON_DESTROY 事件傳送給其觀察者。片段接著會叫用其 onDestroy() 回呼。此時,片段已到達生命週期終點。

其他資源

若要進一步瞭解片段生命週期,請參閱下列其他資源。

指南

網誌