以下各節將說明儲存返回堆疊,以及儲存與返回堆疊項目相關聯狀態的策略。
儲存返回堆疊
為提供良好的使用者體驗,請務必確保應用程式的導覽狀態在各種生命週期事件中保持不變,包括設定變更和程序終止。在 Navigation 3 中,您擁有返回堆疊,因此沒有建立或儲存的嚴格規範。不過,Navigation 3 確實提供了一種便利的方法,可讓您儲存返回堆疊:rememberNavBackStack。
使用rememberNavBackStack
rememberNavBackStack 可組合函式旨在建立返回堆疊,在設定變更和程序終止時仍能保留。
為確保 rememberNavBackStack 正常運作,返回堆疊中的每個鍵都必須符合特定規定:
- 實作
NavKey介面:返回堆疊中的每個索引鍵都必須實作NavKey介面。這個介面可做為標記,向程式庫表示可以儲存金鑰。 - 具有
@Serializable註解:除了實作NavKey之外,您的金鑰類別和物件也必須標示@Serializable註解。
下列程式碼片段顯示 rememberNavBackStack 的正確實作方式:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
記住含有 NavKey 子類型的返回堆疊
rememberNavBackStack 可組合函式會傳回 NavBackStack<NavKey>。如果應用程式定義自己的 NavKey 子類型,且所有索引鍵都繼承自該子類型,您可以實作自訂記住函式,保留該類型,如下所示:
@Serializable sealed interface MyAppNavKey : NavKey @Serializable data object ScreenA: MyAppNavKey @Serializable data class ScreenB(val id: String): MyAppNavKey @Composable fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> { return rememberSerializable(serializer = serializer()) { NavBackStack(*elements) } } @Composable fun MyApp() { // defaultNavBackStack is NavBackStack<NavKey> val defaultNavBackStack = rememberNavBackStack(ScreenA) // myAppNavBackStack is NavBackStack<MyAppNavKey> val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA) }
如需更多範例 (包括如何處理開放多型),請參閱 NavBackStackSamples。
替代方案:儲存在 ViewModel
管理返回堆疊的另一種方法是將其儲存在 ViewModel 中。如要在使用 ViewModel 或任何其他自訂儲存空間時,在程序終止後仍保留資料,您必須:
- 確保金鑰可序列化:與
rememberNavBackStack一樣,導覽金鑰必須可序列化。 - 手動處理序列化和反序列化:當應用程式進入背景或還原時,您必須手動將每個金鑰的序列化表示法儲存至永久儲存空間 (例如
SharedPreferences、資料庫或檔案),並從中反序列化。
將 ViewModel 個執行個體的範圍限定為 NavEntry 個物件
ViewModels 可在設定變更 (例如螢幕旋轉) 時保留 UI 相關狀態。根據預設,ViewModels 的範圍會限定在最接近的 ViewModelStoreOwner,通常是 Activity 或 Fragment。
不過,您可能需要將 ViewModel 的範圍限定在返回堆疊上的特定 NavEntry (即特定畫面或目的地),而非整個 Activity。這樣可確保只有在特定 NavEntry 屬於返回堆疊的一部分時,系統才會保留 ViewModel 的狀態,並在 NavEntry 彈出時清除。
androidx.lifecycle:lifecycle-viewmodel-navigation3 外掛程式庫提供 NavEntryDecorator,可協助您完成這項作業。這個裝飾器會為每個 NavEntry 提供 ViewModelStoreOwner。在 NavEntry 的內容中建立 ViewModel 時 (例如在 Compose 中使用 viewModel()),系統會自動將其範圍限定在返回堆疊上該特定 NavEntry 的索引鍵。也就是說,ViewModel 會在 NavEntry 新增至返回堆疊時建立,並在移除時清除。
如要使用 NavEntryDecorator 將 ViewModel 的範圍限定為 NavEntry,請按照下列步驟操作:
- 在
app/build.gradle.kts檔案中新增androidx.lifecycle:lifecycle-viewmodel-navigation3依附元件。 - 建構
NavDisplay時,請將預設rememberSaveableStateHolderNavEntryDecorator()新增至entryDecorators清單。 - 將
rememberViewModelStoreNavEntryDecorator()新增至entryDecorators清單。
NavDisplay( entryDecorators = listOf( // Add the default decorators for managing scenes and saving state rememberSaveableStateHolderNavEntryDecorator(), // Then add the view model store decorator rememberViewModelStoreNavEntryDecorator() ), backStack = backStack, entryProvider = entryProvider { }, )