每個 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()設定片段最高的生命週期狀態。 - 片段的生命週期狀態不得大於其父項。例如,父項片段或活動必須在其子項片段之前開始。同樣地,子項片段必須在父項片段或活動之前停止。
Lifecycle 狀態及其在片段的生命週期回呼和片段的檢視畫面 Lifecycle 之間的關係。圖 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 級別,呼叫順序則相反。
onStop() 及 onSaveInstanceState() 的呼叫順序差異。建立的片段及刪除的檢視畫面
完成所有離開的動畫及轉換後,片段檢視畫面會從視窗卸離,片段的檢視畫面 Lifecycle 就會移至 DESTROYED 狀態,並將 ON_DESTROY 事件發送給觀察者。片段接著會叫用其 onDestroyView() 回呼。此時,片段的檢視畫面已到達生命週期尾端,getViewLifecycleOwnerLiveData() 會傳回 null 值。
此時,應該移除片段檢視畫面的所有參照,讓片段的檢視畫面能夠成為無用項目收集。
刪除的片段
如果片段遭移除,或是 FragmentManager 被刪除,則片段的 Lifecycle 就會移至 DESTROYED 狀態,並將 ON_DESTROY 事件傳送給其觀察者。片段接著會叫用其 onDestroy() 回呼。此時,片段已到達生命週期終點。
其他資源
若要進一步瞭解片段生命週期,請參閱下列其他資源。