### 錯誤的 Navigation 設計方式:跨模組硬編碼 * Feature A 中直接使用 `navController.navigate(ScreenC.route)` 導向 Feature B 的畫面。 * 此方式造成 Feature A 模組無法被獨立重用,違反模組解耦的原則。 * 導致強耦合於特定的 Navigation 實作(如 Jetpack Compose Navigation)。 * 如果換成其他 Navigation Library(如 Voyager、Compose Destinations)會導致不相容。 --- ### Navigation 的正確責任分層 * 導覽行為應由 `App Module`(應用程式層)統一管理。 * Feature 模組只提供畫面 Composable,使用 `Lambda` 方式暴露互動事件。 * `App Module` 根據實際需求注入對應的 Navigation Lambda,達到完全解耦。 --- ### 修改方式:從 NavController 改為 Lambda 回調 * 在 Feature 畫面中移除 `navController` 使用。 * 改用例如 `onButtonClick: () -> Unit` 回調函式來處理點擊事件。 * 在 `App Module` 的 `MainActivity` 中設定實際的 `navController.navigate(...)` 邏輯。 --- ### 不推薦的 Feature Graphs 實作 * 常見錯誤:每個 Feature 自己實作一份 NavGraph(含 `NavController`)。 * 雖然可行,但仍造成耦合於 Jetpack Compose Navigation API。 * 應避免在 Feature 模組中出現 `navController` 或 `NavGraphBuilder` 的使用。 --- ### 正確設計:App Module 統一組裝 NavGraph * 所有導覽邏輯統一寫在 `MainActivity` 的 NavHost 中。 * 每個 Feature 提供畫面 Composable 並接受事件 Lambda。 * `App Module` 注入所需的 `navigate(...)` 或 `popBackStack(...)` 實作。 --- ### Route 定義應放在 App Module 而非 Navigation Core * 多數人會把所有 Route 放在 Core 模組,但這會讓 Feature 模組知道太多。 * 正確方式是將畫面 Route 定義放在使用該畫面的 `App Module`。 * Feature 模組應僅提供 Composable,不應知道 App 的結構或其他 Feature 存在。 --- ### 建議做法與進階觀念 * 可採用「每個 Feature 一個 Navigation Graph」的方式來提升彈性。 * 這能夠讓 App 在導航時整個移除特定 Feature 的 back stack。 * Multi-module 架構錯誤實作風險高,不熟悉時建議先採單模組架構。 --- ### 結語與建議 * Multi-module 架構強大但容易踩坑,需充分理解模組邊界與責任。 * 若未熟悉 Navigation 解耦設計,應避免在正式專案中使用 Multi-module。 * 維持 Feature 模組的「輸出畫面、暴露事件」原則是解耦的核心。 --- ### Terminology * 多模組架構(Multi-Module Architecture):將應用拆分為多個模組以提升模組化、可重用性與建構效率。 * 應用模組(Application Module):專責組裝與整合所有 feature 模組,管理整體應用邏輯與導覽。 * 功能模組(Feature Module):每個模組專注於一個功能區塊,如登入、使用者資料等。 * 組合式導航(Jetpack Compose Navigation):用於 Compose 應用中的導航解決方案,透過 route 定義目的地。 * navController:Compose 導覽的核心控制器,用來執行 `navigate()`、`popBackStack()` 等。 * route(路由):字串型識別符,用來定義與導覽至特定畫面。 * 屏蔽導覽邏輯(Decoupling Navigation Logic):將導航動作與畫面邏輯解耦,提升模組重用性與可測性。 * Lambda 導覽回呼(Navigation Lambda Callback):使用函式參數方式將導航邏輯由畫面委託至應用模組。 * Compose Destination Library:第三方導航函式庫,提供類似於 Jetpack Navigation 的替代方案。 * Voyager:另一個支援 Compose 的導航函式庫,支援狀態保存與動態導覽。 * 封裝性(Encapsulation):每個模組應該封裝自己的邏輯與 UI,不應依賴其他模組。 * 可重用性(Reusability):模組應能獨立用於不同應用,避免交叉耦合。 * 導覽耦合(Navigation Coupling):當模組內部直接使用 NavController 或指定其他模組 route 時會產生耦合。 * 頂層整合(Top-Level Wiring):應用模組整合所有功能模組,定義畫面之間的導覽流程。 * navigation graph per feature:為每個模組定義獨立導覽圖,有利於功能區塊的清除與管理。 * 單一導覽點(Single Navigation Point):限制 NavController 僅存在於應用模組。 * 導覽責任分離(Navigation Responsibility Separation):導航邏輯應由應用模組負責,而非功能模組。 * NavHost:負責管理導覽畫面的容器,在 Compose 中用於顯示當前畫面。 * 導覽事件回呼(Navigation Event Callback):透過函式參數傳遞用戶操作對應的導覽動作。 * 依賴注入(Dependency Injection):用於模組間解耦的設計模式,與導覽 Lambda 結合能提升彈性。 * Compose 模組導覽誤用(Improper Compose Module Navigation):模組直接持有 NavController,破壞模組化原則。 * 僅應用層使用 NavController:確保 NavController 不外洩至功能模組。 * 路由集中管理(Centralized Route Definition):所有路由定義應集中於應用模組,防止模組間交叉依賴。 * 模組依賴方向(Module Dependency Direction):功能模組不應依賴於其他功能模組,僅應依賴核心模組。 * 模組可測試性(Testability):無導覽耦合的模組可獨立進行單元與 UI 測試。 * 導覽動作委託(Delegated Navigation Actions):導航控制邏輯由上層注入,功能模組僅觸發事件。 * 測試替代性(Test Substitution):導覽回呼可於測試中被替換為其他動作以驗證功能正確。 * 導覽內聚(Navigation Cohesion):將相同模組內的畫面導覽邏輯集中管理。 * 返回棧管理(Back Stack Management):使用 `popUpTo()` 或 `popBackStack()` 管理畫面返回行為。 * 畫面重用性(Screen Reusability):畫面不應綁定特定應用導覽流程,提升通用性。 * Feature Graph 移除(Removing Feature Graph):避免功能模組內建立 NavGraph 以免耦合至 Compose Navigation。 * 畫面邏輯與導覽解耦(Screen vs Navigation Decoupling):畫面僅負責觸發事件,導覽由上層處理。 * 無框架依賴(Library Independence):模組不依賴特定導覽框架以提升跨專案移植性。 * DSL 過度耦合風險(DSL Overbinding Risk):過度依賴 Compose DSL 的導覽寫法會增加模組綁定。 * 應用整合自由度(App-Level Integration Freedom):應用模組可自由組合模組,不受模組內部邏輯限制。 * 導覽轉發策略(Navigation Dispatch Strategy):透過抽象介面或函式型參數統一處理導覽指令。 * 動作名稱語義化(Semantic Action Naming):為 Lambda 命名如 `onLoginClick` 提升可讀性與可維護性。 * 事件導向導覽(Event-Driven Navigation):畫面以事件形式觸發導航,增強模組可測試性。 * PopUpTo 使用(popUpTo Usage):刪除返回棧中指定畫面,常用於流程結束後清除歷史畫面。 * Inclusive 屬性(Inclusive Flag):控制 pop 行為是否包含目標目的地。 * 模組畫面構建原則(Modular Screen Construction Principle):畫面僅定義 UI 和事件,不參與導覽流程。 * Context-Agnostic Modules:模組應該不關心其所屬應用的實作背景與導覽規則。 * 畫面暴露(Screen Exposure):模組僅暴露 Composable 作為使用者介面入口。 * 導覽管理層(Navigation Management Layer):集中於應用層負責導覽切換與狀態管理。 * compose-navigation decoupling:切斷模組與 compose-navigation 函式庫的直接依賴關係。 * 應用層導航地圖(App-Level Navigation Map):完整定義應用畫面與導覽流程的結構圖。 * Gradle 加速(Gradle Build Acceleration):正確模組化有助於並行建構與加快 build 速度。 * 導覽穩定性(Navigation Stability):集中導覽實作能減少路由錯誤與錯誤路徑。 * 非功能模組導航封裝(Non-Feature Navigation Wrapping):將功能模組之外的導覽邏輯集中於應用層。 * Compose 導覽框架透明化(Navigation Framework Abstraction):模組不暴露其所用導航框架細節,提供框架替換彈性。 * 資源共用限制(Shared Resource Constraint):功能模組不應依賴應用層資源以維持邊界清晰。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up