將 Jetpack Navigation 遷移至 Navigation Compose

Navigation Compose API 可讓您瀏覽 Compose 應用程式,同時利用 Jetpack Navigation 元件 基礎架構與功能

本頁面說明如何從以 Fragment 為基礎的 Jetpack Navigation 遷移至 Navigation Compose,參與以 View 為基礎的大型 UI 遷移至 Jetpack 。

遷移作業必備條件

等到您能替換所有 具有對應畫面可組合項的片段。螢幕可組合項可包含 混合使用 Compose 和 View 內容,但所有導覽到達網頁都必須 可組合項來啟用 Navigation Compose 遷移功能。在此之前, 請繼續在互通性檢視畫面中使用以片段為基礎的 Navigation 元件, Compose 程式碼集。詳情請參閱導覽互通性說明文件 可能不準確或不適當

即使在僅支援 Compose 的應用程式中使用 Navigation Compose 也不是必要條件。你可以 繼續使用 以片段為基礎的 Navigation 元件 用於代管可組合項內容的片段。

遷移步驟

無論您是採用我們建議的遷移策略,還是 另一種做法,您會到達所有導覽目的地所在的位置 螢幕可組合項,其中 Fragments 只能做為可組合容器。在此 就可以遷移至 Navigation Compose。

如果您的應用程式已遵循 UDF 設計模式 遷移至 Jetpack Compose 和 Navigation Compose 時應該不會 需要應用程式其他層的主要重構 (除了 UI 層之外)。

如要遷移至 Navigation Compose,請按照下列步驟操作:

  1. 在應用程式中新增 Navigation Compose 依附元件
  2. 建立 App-level 可組合函式,並將其新增為 Activity 中, Compose 進入點,取代 View 版面配置的設定:

    class SampleActivity : ComponentActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            // setContentView<ActivitySampleBinding>(this, R.layout.activity_sample)
            setContent {
                SampleApp(/* ... */)
            }
        }
    }

  3. 在需要所有需要可組合項的地方設定 NavController ,就可以參照 (通常位於 App 中) 可組合函式)。這個方法符合狀態提升的原則, 可讓您使用 NavController 做為瀏覽的可靠資料來源 如何切換可組合項畫面及維護返回堆疊:

    @Composable
    fun SampleApp() {
        val navController = rememberNavController()
        // ...
    }

  4. 在應用程式可組合項中建立應用程式的 NavHost,並傳遞 navController

    @Composable
    fun SampleApp() {
        val navController = rememberNavController()
    
        SampleNavHost(navController = navController)
    }
    
    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = "first") {
            // ...
        }
    }

  5. 新增 composable 目的地以建構導覽圖。如果每個 畫面先前已遷移至 Compose,但這個步驟只包含 將這些螢幕可組合項從 Fragment 擷取至 composable 目的地:

    class FirstFragment : Fragment() {
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
            return ComposeView(requireContext()).apply {
                setContent {
                    // FirstScreen(...) EXTRACT FROM HERE
                }
            }
        }
    }
    
    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = "first") {
            composable("first") {
                FirstScreen(/* ... */) // EXTRACT TO HERE
            }
            composable("second") {
                SecondScreen(/* ... */)
            }
            // ...
        }
    }

  6. 如果您已按照建構 Compose UI 的指南操作, 特別是應如何傳遞 ViewModel 和導覽事件至 可組合函式,下一步是變更提供 ViewModel 以 每個螢幕可組合項您可以經常使用 Hilt 插入及其整合功能 透過 hiltViewModel 使用 Compose 和 Navigation:

    @Composable
    fun FirstScreen(
        // viewModel: FirstViewModel = viewModel(),
        viewModel: FirstViewModel = hiltViewModel(),
        onButtonClick: () -> Unit = {},
    ) {
        // ...
    }

  7. 將所有 findNavController() 導覽呼叫替換為 navController 並將這些事件做為導覽事件傳遞至每個可組合函式畫面 而不是傳遞整個 navController這個方法遵循 從可組合函式向呼叫端公開事件的做法 保留 navController 做為單一可靠資料來源。

    1. 如果您先前已使用 Safe Args 外掛程式產生 應替換為導航路線和動作,並替換為路線。 可組合元件的字串路徑,每個目的地都不得重複。
    2. 如需在傳遞資料時取代 Safe Args,請參閱使用 引數
    3. 如需 Navigation Compose 的類型安全性,請參閱 Safe Args 一節

      @Composable
      fun SampleNavHost(
          navController: NavHostController
      ) {
          NavHost(navController = navController, startDestination = "first") {
              composable("first") {
                  FirstScreen(
                      onButtonClick = {
                          // findNavController().navigate(firstScreenToSecondScreenAction)
                          navController.navigate("second_screen_route")
                      }
                  )
              }
              composable("second") {
                  SecondScreen(
                      onIconClick = {
                          // findNavController().navigate(secondScreenToThirdScreenAction)
                          navController.navigate("third_screen_route")
                      }
                  )
              }
              // ...
          }
      }

  8. 移除所有 Fragment、相關的 XML 版面配置、不必要的導覽和其他 以及過時的 Fragment 和 Jetpack Navigation 依附元件

您也可以在 設定說明文件

常見用途

無論您使用何種 Navigation 元件, 導覽元件

遷移作業的常見用途包括:

如需更多有關這些用途的詳細資訊,請參閱使用 撰寫

Safe Args

與 Jetpack Navigation 不同,Navigation Compose 不支援使用 Safe Args 外掛程式用於產生程式碼。相反地,您可以利用 Navigation Compose逐步建構程式碼,確保程式碼在 執行階段。

瀏覽時擷取複雜資料

Navigation Compose 是以字串路徑為基礎,與 Jetpack Navigation 不同, 不支援傳遞自訂 Parcelable 和 Serializables 做為引數

強烈建議您不要在導覽時傳遞複雜的資料物件。 請改為傳送最低限度資訊,例如專屬 ID 或 其他形式的 ID 做為引數請 將複雜物件儲存為單一可靠資料來源中的資料,例如資料 資料層如需詳細資訊,請參閱擷取複雜資料的時機 導航

如果 Fragment 將複雜物件做為引數傳遞,請考慮重構 並優先存取 資料層請參閱 Now in Android 存放區: 範例。

限制

本節說明 Navigation Compose 目前的限制。

逐步遷移至 Navigation Compose

目前您無法在使用 Fragment 做為 加入到達網頁如要開始使用 Navigation Compose, 目的地必須是可組合函式。您可以在 Issue Tracker

轉場動畫

Navigation 2.7.0-alpha01 開始支援設定自訂功能 原先來自AnimatedNavHost的轉場效果 直接支援 NavHost。詳閱版本資訊 瞭解詳情

瞭解詳情

如要進一步瞭解如何遷移至 Navigation Compose,請參閱下列文章 資源: