### Navigation 3 推出的背景與目的
* 提供更簡潔、符合 Compose 思維的 API
* 解決舊版 navigation 無法直接控制 backstack 的問題
* 支援多畫面(Multi-pane)場景,適用於平板、桌面與 Web
* 為多平台(Kotlin Multiplatform)而設計,未來將強化 Web 支援
---
### Backstack 與 Key 的概念
* Backstack 是一個記錄畫面順序的資料結構,內容是 key 而非實體畫面
* Key 為可序列化的資料類別,需實作 NavKey 介面
* Backstack 可用 rememberNavBackstack 建立,並能保存與還原狀態
* 管理 backstack 僅需操作 List 結構,如新增或移除元素
---
### NavDisplay 取代 NavHost
* NavDisplay 是導航的主要容器,需傳入 backstack
* 不再需要 NavController,改由直接操作 backstack
* NavDisplay 接收 entryProvider,決定要渲染哪個畫面
* 可傳入 entryDecorators 添加額外行為(如 ViewModel 支援、狀態保存)
---
### EntryProvider 的使用方式
* 接收 key 並根據其型別選擇要顯示的畫面
* 每個畫面需用 NavEntry 包裝,並傳入對應的 key 與 Composable
* 可使用 DSL 替代 when 判斷,使語法更簡潔
* 如無符合的 key,建議拋出例外避免錯誤畫面顯示
---
### 實作畫面與導覽流程
* 建立 NoteListScreen 作為起始畫面,顯示列表項目
* 建立 NoteDetailScreen 並接受 ID 參數,用於顯示指定筆記內容
* 當列表項目被點擊時,將 NoteDetailScreen 實例加到 backstack 中即完成導覽
* 返回時移除最後一個 backstack 元素即可回上一頁
---
### ViewModel 的支援方式
* 可使用 ViewModel 搭配 Navigation Tree 提供的 decorator 進行畫面綁定
* ViewModel 可依據單一 nav entry 綁定生命週期
* 當畫面被移除出 backstack 時,ViewModel 也會一併清除
---
### 自定義 Entry Decorators
* Decorator 是擴充行為的機制,能攔截並處理每一次導航邏輯
* 官方提供 ViewModel、狀態保存、Scene 支援等預設 decorators
* 可自定義 decorator,類似 Retrofit 的 Interceptor 設計模式
---
### 總結 Navigation 3 的關鍵特色
* 完整控制 backstack,結構清晰、操作直覺
* 不依賴 NavController,導覽邏輯更靈活
* 更好整合 ViewModel 與畫面狀態
* 更適合複雜畫面、跨平台與大型專案使用
* API 設計簡潔,貼近 Compose 架構核心理念
---
### 建立 Note 資料類別與樣本資料
* 建立 `Note` 資料類別,包含 id、title、content 和 color。
* 產生 100 筆樣本筆記,並隨機產生顏色,設定透明度避免文字難以閱讀。
---
### 顯示 Note 列表畫面(NodeListScreen)
* 使用 `LazyColumn` 顯示樣本筆記列表。
* 每項筆記以 `Column` 呈現,內含 title 和 content。
* 點擊筆記時觸發 `onNoteClick` callback 傳遞筆記 ID。
---
### 設定導覽邏輯與 Backstack 操作
* 在 `NavigationRoot` 中接收筆記 ID,透過 `backstack.add` 推送對應的 `NoteDetailScreen`。
* 移除畫面則使用 `backstack.removeLast()`,等同舊版 `popBackStack()`。
* 示範可對 backstack 進行任意操作(如重排、重複推入、移除)以驗證靈活性。
---
### 使用 ViewModel 顯示筆記詳情
* 建立 `NoteDetailViewModel`,內含 `MutableStateFlow<Note>` 用於儲存當前筆記。
* 不再從 `SavedStateHandle` 取得導航參數(在 alpha 階段不支援)。
* 改為透過建構子明確接收參數(如筆記 ID)。
---
### 與 Koin 整合 ViewModel 與參數注入
* 使用 `viewModelOf()` 註冊 ViewModel 至 Koin。
* 建立 Application 類別啟用 Koin,並於 `AndroidManifest.xml` 中註冊。
* 使用 `getViewModel(parameters = { parametersOf(id) })` 傳遞參數給 ViewModel。
---
### 在 Composable 中觀察 ViewModel 狀態
* 使用 `collectAsStateWithLifecycle()` 觀察 ViewModel 的筆記資料。
* 將筆記內容渲染在詳情畫面上,顯示 title、content 與背景色。
---
### 將 Backstack 儲存在 ViewModel 中(進階)
* 可將 `MutableStateList<NavKey>` 存於 ViewModel 中,提升測試與控制能力。
* Backstack 須自行處理儲存與還原(process death 時會遺失狀態)。
* 儲存方式可透過檔案或 SharedPreferences 進行序列化還原。
* 好處是可在單元測試中驗證導航邏輯,無需啟動 UI。
---
### 系統行為與備註
* 使用 `rememberNavBackstack()` 時,系統會自動保存與還原 backstack 狀態。
* 若使用自訂 backstack(如放入 ViewModel),需自行處理恢復流程。
* 示範透過模擬 process death(Logcat 中 kill process),系統能還原畫面。
---
### Scenes 基本概念
* Scenes 是 Navigation 3 的新功能,用來組合多個畫面同時顯示
* 每個畫面仍維持獨立狀態與 ViewModel
* 適用於平板、橫向裝置等大螢幕情境
* 常見用法是 two-pane(列表 + 詳細畫面)
---
### Dialog Scene 使用方式
* 內建支援對話框形式的場景呈現
* 利用 metadata 設定該畫面以 Dialog 顯示
* 使用 `dialogSceneStrategy` 套用邏輯
* Dialog Scene 可同時顯示兩個畫面(主畫面與對話框)
---
### 自訂 Two-pane Scene
* 建立自訂 Scene 類別 TwoPaneScene,實作 `Scene<T>`
* 使用 Row 佈局呈現左右兩個畫面
* 左右畫面皆以 nav entry 顯示,可自訂寬度比重
* 保持每個畫面邏輯獨立、支援單獨 ViewModel
---
### 自訂 Scene Strategy 判斷條件
* 建立 TwoPaneSceneStrategy,實作 `SceneStrategy<T>`
* 使用 WindowSizeClass 檢查是否為中等以上寬度裝置
* 當 backstack 最後兩項 metadata 含有 twoPane 標記且裝置符合寬度要求時套用 two-pane scene
* 回傳 previousEntries 決定返回行為,通常為移除最上層畫面後的狀態
---
### 實作限制與錯誤現象
* 在平板或橫向時 two-pane 可正常顯示列表與詳細畫面
* 點擊其他項目進行導航時會導致 crash
* 錯誤訊息為 nav key 重複使用
* 該錯誤也發生在 Google 官方範例中,非使用者實作問題
---
### 動畫與返回手勢支援
* 支援過場動畫與返回動畫設定
* 可設定 `transitionSpec`、`popTransitionSpec`、`predictivePopTransitionSpec`
* 預測性返回動畫(predictive back)可顯示導航目標預覽
---
### 現階段功能限制
* 尚未支援 Nested Nav Graph 功能
* `NavEntryWrapper` 無法處理多個畫面群組
* 尚未提供深度連結(deep link)內建支援
* 若需處理 deep link,需自行處理 intent 並控制 backstack
---
### Terminology
* **Navigation 3**:Jetpack 最新的 Compose 導航函式庫,重構設計、去除 `NavController`,改以 `NavDisplay` 和 Backstack 控制導覽流程。
* **NavDisplay**:新版的導航入口 Composable,取代傳統的 `NavHost`,接收 `backstack` 與 `entryProvider`。
* **Backstack**:開發者可自建的可變堆疊資料結構,用於控制目前與歷史畫面堆疊。
* **NavKey**:標示為可作為導覽目的地的類型,所有 Backstack 中的元素都需實作此介面。
* **Serializable Annotation**:標記 `NavKey` 類別可序列化,便於儲存與還原導覽狀態。
* **rememberNavBackstack**:建構並記憶導覽 Backstack 的 Composable,支援狀態保存與還原。
* **EntryProvider**:依據 `NavKey` 提供對應的 `NavEntry`,用於繪製實際 Composable 畫面。
* **NavEntry**:封裝實際畫面的物件,含畫面鍵值 (`key`) 與 Composable 畫面內容。
* **EntryDecorators**:套用至 `NavDisplay` 的裝飾器,可擴充導航行為(如 ViewModel 管理、狀態保存)。
* **rememberViewModelStoreNavEntryDecorator**:將 ViewModel 的生命週期綁定至單一畫面 (`NavEntry`)。
* **rememberSavedStateNavEntryDecorator**:支援畫面狀態的保存與還原(如旋轉後還原 Backstack)。
* **rememberSceneSetupNavEntryDecorator**:設定場景顯示行為,如多畫面配置(後續可能應用於多窗格 UI)。
* **Composable Navigation**:畫面以 Composable 函數表示,並透過鍵值切換顯示內容。
* **Type-Safe Navigation**:以型別安全的方式管理畫面與其參數(利用 `data class` 表示畫面與傳遞資料)。
* **NavKey Matching**:使用 `when` 或 DSL 方式比對 `NavKey` 並渲染對應畫面。
* **Composable Routing via NavKey**:畫面導覽以 `NavKey` 為基礎,不再依賴 route 字串。
* **Dynamic Backstack Manipulation**:可依任意邏輯新增、刪除或重排序 `Backstack` 元素。
* **Initial Backstack Configuration**:可自訂應用啟動時的初始 Backstack 內容。
* **Decoupled Navigation Logic**:導覽行為不再綁定至 Composable 本身,利於模組重用。
* **Multiplatform Compatibility**:支援 Compose Multiplatform,與 iOS、Web 架構兼容性設計。
* **WindowSizeClass**:可偵測裝置大小分類,便於針對不同螢幕尺寸設計導覽行為。
* **Adaptive Navigation**:支援不同尺寸與平台上適應式的導覽行為與 UI 呈現。
* **Modifier Forwarding**:允許將修飾器向下傳遞至內部元件,保持版面一致性。
* **Manual Pop Behavior**:不再有 `popBackStack`,需手動從 Backstack 刪除頂層項目。
* **Composable Entry Point**:每個畫面透過 `NavEntry` 封裝作為進入點進行顯示。
* **Composable List Navigation**:可為清單項目建立對應的 `NavKey` 並切換畫面至詳細頁。
* **Metadata in NavEntry**:可選擇性為 `NavEntry` 添加額外資料,支援進階畫面需求。
* **Exhaustive NavKey Matching**:完整列舉每一個 `NavKey` 類型,以確保畫面轉換邏輯明確。
* **NavEntry Lifecycle Scoping**:每個 `NavEntry` 可擁有獨立生命週期管理(例如 ViewModel)。
* **State Restoration after Process Death**:程式重啟後自動還原導覽狀態,提升使用者體驗。
* **EntryProvider DSL**:DSL 形式的 `entryProvider` 提供更簡潔清晰的畫面定義。
* **Flexible Start Destination**:可任意指定初始畫面,包含帶參數的畫面。
* **Navigation Logic as Data**:將導覽定義轉換為資料(key)操作,提升測試與預測性。
* **Multiple NavDisplays**:可依需求同時定義多組 `NavDisplay`,支援多畫面結構。
* **Scene Support**:實驗性場景功能(可能支援動畫切換、多窗格畫面等進階 UI)。
* **EntryDecorator Customization**:開發者可自行實作裝飾器,自訂導覽行為(類似攔截器)。
* **BackStack UI Decoupling**:UI 呈現與 Backstack 邏輯完全分離,利於模組化與單元測試。
* **Composable Injection via Koin**:與 Koin 整合支援 Composable 中的依賴注入與 ViewModel 注入。
* **JetBrains Kotlin Serialization Plugin**:使用 `kotlinx.serialization` 處理參數序列化與還原。
* **Mutable State List for Backstack**:Backstack 為 Compose 的 `SnapshotStateList`,支援狀態觀察。
* **Activity-Level Scoping(ViewModel)**:預設 ViewModel 為 Activity 層級,可透過 Decorator 降階。
* **Compose-Only Navigation Paradigm**:完整移除 XML,全部導航邏輯與 UI 行為皆於 Compose 完成。
* **Composable Interoperability**:新導航架構與 Compose 所有特性(狀態、生命周期)高度整合。
* **Scalable Navigation System**:適合中大型應用,支援動態 Backstack 管理與高彈性路由控制。
* **Compose-First Declarative API**:設計上完全以 Compose 宣告式程式風格為優先,簡化開發心智負擔。
* **Note Data Class**:用於表示筆記資料的資料類別,通常包含 ID、標題、內容與顏色等屬性。
* **Color Alpha**:使用 `.copy(alpha = 0.5f)` 設定顏色透明度,避免背景顏色影響文字可讀性。
* **Sample Notes**:以亂數產生 100 筆測試用的筆記清單,常用於 UI 測試與展示。
* **LazyColumn**:Jetpack Compose 提供的高效能垂直列表組件,用來顯示多筆資料。
* **Modifier.fillMaxWidth()**:設定組件寬度填滿可用空間。
* **Clickable Modifier**:讓某個 Composable 可點擊,並觸發對應的 lambda 回調。
* **Composable Callback Navigation**:透過 lambda 傳遞點擊事件至上層導覽邏輯,保持畫面模組的解耦。
* **Backstack.addLast()**:將新的 `NavKey` 加入堆疊頂端,相當於進行畫面導覽。
* **Backstack.removeLastOrNull()**:從堆疊中移除最上層的畫面,對應於返回上一畫面。
* **Backstack.shuffle()**:任意打亂 backstack 中的畫面順序,雖非實務常用但展現高度彈性。
* **NavKey Naming Conflict**:避免畫面資料類與畫面 UI 函數同名,建議以 `UI` 後綴區分。
* **ViewModel Integration**:在每個畫面中透過 ViewModel 處理邏輯與狀態管理。
* **ViewModelScope Lifecycle**:藉由 decorator 將 ViewModel 的生命週期綁定至特定畫面 (`NavEntry`)。
* **SafeStateHandle 缺失**:在 Navigation 3 中不再預設注入 `SafeStateHandle`,需改為手動傳參。
* **Koin ViewModel Injection**:使用 Koin 進行 ViewModel 的依賴注入與參數初始化。
* **Koin Parameters Injection**:透過 `parametersOf(...)` 明確傳入 ViewModel 所需參數。
* **Android Application Class**:用來初始化 Koin 或其他應用層級設定。
* **Nav Argument via ViewModel Constructor**:透過建構式參數將畫面資料傳遞給 ViewModel。
* **MutableStateFlow for UI State**:在 ViewModel 中以 `MutableStateFlow` 管理與曝露 UI 狀態。
* **collectAsStateWithLifecycle()**:Compose 與 Flow 整合,且考慮生命週期的狀態收集函式。
* **@Serializable NavKey**:所有用於導覽的鍵必須實作 `NavKey` 並標註為 `@Serializable`。
* **ViewModel Navigation Context**:ViewModel 可擁有 backstack,進而掌握目前畫面與導覽邏輯。
* **Persistent Backstack via RememberNavBackstack**:使用此函式自動處理導覽堆疊的保存與還原。
* **Manual Backstack Persistence**:若將 backstack 移入 ViewModel,需自行序列化並保存狀態。
* **SnapshotStateList**:Compose 提供的可觀察 List 型狀態容器,支援資料變動自動更新 UI。
* **Testing Navigation in ViewModel**:允許在單元測試中模擬與驗證畫面導覽邏輯。
* **Composable-based Argument Propagation**:導覽參數不再自動注入,需開發者明確提供。
* **Global Navigation ViewModel**:若需全域導覽控制,可建立一個管理整體 backstack 的 ViewModel。
* **Preference/Local Storage Backstack Saving**:將 backstack 存入偏好設定或檔案,支援進階還原需求。
* **Compose Navigation Debugging**:可視化與操作 backstack,協助開發與除錯。
* **Navigation Flexibility via Data Structure**:將導航邏輯轉為資料結構操作(如 list),提高彈性。
* **ViewModel Reusability Across Screens**:能依據不同畫面重複使用 ViewModel 並注入不同參數。
* **Composable ↔ ViewModel Clear Separation**:畫面僅處理顯示,邏輯完全由 ViewModel 控制。
* **Koin Integration Best Practice**:明確注入所需型別參數,避免 ViewModel 無法正確建構。
* **OnCreate Application DI Bootstrapping**:於應用啟動時進行 DI 框架初始化。
* **Color.fromLong()**:從 `Long` 整數轉為 Compose 支援的 `Color`。
* **FontSize with sp()**:字體大小使用 `sp` 單位,符合使用者系統偏好設定。
* **Composable Padding & Spacing**:以 `padding` 與 `Spacer` 控制畫面間距與留白。
* **Composable Preview with Data**:使用靜態資料作為 Compose 畫面預覽來源。
* **State Restoration Testing via Kill Process**:透過模擬殺死程序,測試狀態保存與導覽還原。
* **Custom NavEntry Behavior via Decorators**:自訂畫面生命週期與附加行為(例如 ViewModel 清理)。
* **Navigation Parameter Testing**:驗證傳遞參數後畫面與資料是否正確更新。
* **DI Module Structure**:建立清晰模組化的依賴注入架構,如 `AppModule`。
* **ViewModel Initialization Strategy**:依據參數是否複雜選擇預設建構或手動注入。
* **NavKey Routing Granularity**:每個畫面皆有明確鍵值與資料來源,利於可測試性與重用性。
* **In-memory Static Content Limitation**:靜態資料如列表於重建後變化,可反映為狀態保存範例。
* **Process Death & Restoration Awareness**:開發者需理解 Android 系統行為並妥善應對。
* **Clear Exception on Missing Match**:明確拋出例外而非使用 `else` 處理,增強可讀性與除錯能力。
* **Composable Name Conflict Resolution**:推薦將 Composable 函數名稱與資料類名稱區分。
* **Compose Function Rename via Shift + F6**:利用快捷鍵避免重名與 IntelliJ 衝突。
* **ViewModel Injection via DI Framework**:簡化初始化,避免手動建構依賴。
* **Backstack as a Navigation State Source**:導覽不再由控制器主導,而是由狀態變動驅動畫面更新。
* **Scenes**:在 Navigation 3 中,Scene 是一種組合畫面的方式,可將多個畫面組合在一起顯示(如對話框、多欄畫面)。
* **TwoPane Scene**:特定的 Scene 類型,將兩個畫面並排顯示,常用於平板裝置或寬螢幕。
* **Dialog Scene Strategy**:將畫面以對話框形式呈現的策略,常搭配對話場景使用。
* **Scene Strategy**:用來定義在什麼情況下套用哪一種 Scene,如依螢幕尺寸選擇單欄或雙欄。
* **Scene Metadata**:用於標註特定畫面是否符合某 Scene 條件的標記資料(例如兩欄或對話框)。
* **Row + Modifier.weight()**:在 Scene 中以 `Row` 配合 `weight` 決定畫面分配寬度比例。
* **NavEntry**:單一畫面的實例與內容包裝,可用於 Scene 組合。
* **Previous Entries**:定義當使用者按返回鍵時 Scene 該如何回退(通常回到上一個 Entry)。
* **Scene.content()**:定義自訂 Scene 如何顯示內容,實作畫面排列邏輯。
* **CurrentWindowAdaptiveInfo**:提供當前裝置的視窗資訊,判斷是否為平板或橫向。
* **Breakpoint.Dp.Medium**:代表中等尺寸的螢幕界線,常用於切換單欄與雙欄場景。
* **entries.dropLast(1)**:移除 backstack 最後一個元素,用以指定 Scene 的 previousEntries。
* **entries.takeLast(2)**:取 backstack 的最後兩個畫面,判斷是否要合併顯示為 Scene。
* **Scene Strategy.calculateScene()**:決定是否與如何套用 Scene 的邏輯方法。
* **NavEntry.content(key)**:呼叫特定 Entry 的內容顯示 Composable。
* **DialogProperties**:自訂對話框樣式屬性,例如不可取消、模糊背景等。
* **Scene Companion Object**:集中管理 Scene 所需常數與 metadata keys。
* **Scene Metadata Map**:每個畫面傳遞額外資料的方式,用於判斷是否加入某 Scene。
* **Predictive Back Animation**:Android 14+ 的返回預覽手勢動畫,Navigation 3 提供支援。
* **TransitionSpec**:自訂畫面切換動畫規格的方式,包括 `popTransitionSpec`。
* **PredictivePopTransitionSpec**:針對返回預覽提供動畫過渡效果。
* **NavDisplay.transitionSpec**:在 Navigation 3 的核心組件中設置轉場動畫。
* **Scene Invocation on Tablet**:當裝置為平板並符合條件時,Scene 自動生效顯示多畫面。
* **Backstack Key Conflict Bug**:目前場景下存在 key 重複錯誤問題,為已知 alpha 版本限制。
* **Scene State Sharing**:允許每個畫面獨立使用 ViewModel,同時在一個場景中共存。
* **ViewModel Scope in Scenes**:即使畫面同時顯示,每個畫面仍擁有自己生命週期綁定的 ViewModel。
* **Deep Link Manual Handling**:目前需手動處理深連結,例如使用 `onNewIntent()`。
* **NavEntryWrapper**:提供對單一 `NavEntry` 的額外封裝,但不支援多畫面整合。
* **No Nested Graph Support**:目前未提供類似舊版 Nested Graph 的群組畫面與共享 ViewModel 支援。
* **Navigation Bug Traced to Google Sample**:相同錯誤亦出現在 Google 原始碼中,推測為底層問題。
* **Compose Scene Flexibility**:開發者可自定 Scene 排列樣式,例如橫排、網格、重疊等。
* **Grid Layout Scene (2x2)**:Scene 可擴展成多欄或網格顯示應用場景。
* **Metadata-driven Scene Application**:Scene 應用完全取決於 metadata 與 strategy 評估。
* **Single Scene Strategy Limitation**:每次只能設一個 sceneStrategy,需在其中整合多種邏輯。
* **Adaptive Layout Responsiveness**:自動依螢幕大小切換場景設計,提高跨裝置兼容性。
* **Composable Independence in Scene**:即便畫面同時呈現,每個畫面 Composable 可單獨開發與測試。
* **Scene-centric Navigation Modeling**:導覽模式轉為以場景為核心組合,而非單一畫面跳轉。
* **Backstack-as-State Foundation**:場景變換建立在 backstack 這個可觀察狀態資料結構上。
* **NavEntry.key Uniqueness Required**:每個畫面需保證唯一 key,以避免重複錯誤。
* **Scene Conflict Error Trace**:常見錯誤提示為 “Key used multiple times”,與 metadata 設定衝突有關。
* **Orientation-based Scene Switching**:以橫/直向切換 Scene 排列方式,增進 UX。
* **Jetpack Compose Recomposition Control**:Scene 排列可避免不必要重組,提高效能。
* **ViewModel Retention per NavEntry**:每個 NavEntry 與 ViewModel 綁定可精準管理狀態與生命週期。
* **Composable Isolation in Layout**:Scene 實現時保持 Composable 相互隔離,避免邏輯耦合。
* **Composable Weight for Flexible Layout**:使用 `weight` 控制 Scene 組件的空間分配。
* **Back Handling per Scene**:Scene 可自訂返回邏輯,如同時關閉兩畫面或只退一層。
* **Preview-friendly Scene Architecture**:可將 Scene 作為單元獨立預覽與測試。
* **Testing Scene Transitions**:Scene 可配合 UI 測試驗證排列與互動邏輯。
* **Future-proof Layout Design**:Scene 設計便於擴充應對未來 UI 需求(折疊裝置等)。
* **Adaptive + Scene Synergy**:結合 Adaptive Layout 判斷與 Scene 排列,實現多裝置最佳體驗。