每個 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
之間的關係。
一個片段會在生命週期中不斷演進,因此狀態會往上或向下移動。例如,新增至返回堆疊頂端的片段會從 CREATED
上移至 STARTED
再到 RESUMED
。反之,如果片段從返回堆疊中移除,就會從狀態中向下移動,從 RESUMED
到 STARTED
到 CREATED
並最後到 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
執行個體,其回呼會更新片段的檢視畫面,並在片段的檢視畫面中對任何 RecyclerView
或 ViewPager2
的執行個體設定配接器。
已建立的片段及檢視畫面
建立片段的檢視畫面後,若有先前的檢視畫面,系統就會將其狀態還原,該檢視畫面的 Lifecycle
則改為 CREATED
狀態。檢視畫面生命週期的擁有者也會將 ON_CREATE
事件發送給其觀察者。在這裡,您應該還原任何其他與片段檢視畫面有關的狀態。
此轉換作業也會叫用 onViewStateRestored()
回呼。
已開始的片段及檢視畫面
強烈建議您將生命週期感知元件連結到片段的 STARTED
狀態,因為此狀態可以確保片段的檢視畫面可以使用(如果已產生),而且能夠在片段的子項 FragmentManager
上安全執行 FragmentTransaction
。如果片段的檢視畫面不是空值,則在片段的 Lifecycle
移至 STARTED
後,片段檢視畫面的 Lifecycle
就會立即移至 STARTED
。
片段變成 STARTED
時,就會叫用 onStart()
回呼。
重新啟用的片段及檢視畫面
片段顯示時,所有 Animator
和 Transition
效果皆已完成,該片段已可供使用者使用。片段的 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 級別,呼叫順序則相反。
建立的片段及刪除的檢視畫面
完成所有離開的動畫及轉換後,片段檢視畫面會從視窗卸離,片段的檢視畫面 Lifecycle
就會移至 DESTROYED
狀態,並將 ON_DESTROY
事件發送給觀察者。片段接著會叫用其 onDestroyView()
回呼。此時,片段的檢視畫面已到達生命週期尾端,getViewLifecycleOwnerLiveData()
會傳回 null
值。
此時,應該移除片段檢視畫面的所有參照,讓片段的檢視畫面能夠成為無用項目收集。
刪除的片段
如果片段遭移除,或是 FragmentManager
被刪除,則片段的 Lifecycle
就會移至 DESTROYED
狀態,並將 ON_DESTROY
事件傳送給其觀察者。片段接著會叫用其 onDestroy()
回呼。此時,片段已到達生命週期終點。
其他資源
若要進一步瞭解片段生命週期,請參閱下列其他資源。