Bermigrasi ke Navigation 3

Navigation 3 merepresentasikan perubahan mendasar dalam cara Jetpack Compose menangani status navigasi dan menawarkan keunggulan arsitektur yang signifikan dibandingkan Navigation 2.

Pahami perubahan arsitektur dan langkah-langkah yang diperlukan untuk memigrasikan aplikasi Wear Compose dari Navigation 2 ke Navigation 3.

Keunggulan utama Navigation 3

  • Kontrol Tumpukan Kembali Langsung: NavBackStack pada dasarnya hanyalah daftar objek NavKey yang dapat diubah, yang merepresentasikan histori layar yang telah dikunjungi pengguna. Anda mengontrolnya persis seperti Anda mengontrol MutableList Kotlin (add, removeLast, clear). Anda memanipulasi daftar secara langsung untuk melakukan tindakan navigasi, seperti menambahkan kunci untuk maju atau menghapus kunci untuk kembali.
  • Desain Mengutamakan Compose: Stack kembali dimodelkan sebagai status yang dapat diamati standar. Mengubah histori navigasi Anda berperilaku persis seperti mengupdate status Compose lainnya, yang secara otomatis memicu rekomposisi untuk menampilkan layar saat ini.
  • Type-Safe by Default: Rute berbasis string dihilangkan sepenuhnya. Navigasi menggunakan objek data dan class data yang dapat diserialisasi.
  • Presentasi yang Tidak Terikat (Strategi Adegan): Lapisan transisi UI (NavDisplay dan SwipeDismissableSceneStrategy) sepenuhnya dipisahkan dari pelacakan status (NavBackStack), sehingga memungkinkan integrasi transisi navigasi Wear OS bawaan yang lebih sederhana.

Langkah-langkah migrasi

1. Memperbarui dependensi

Hapus dependensi androidx.wear.compose:compose-navigation lama dan perkenalkan dependensi Navigation 3 split baru, beserta dukungan serialisasi Kotlin.

Hapus:

implementation("androidx.wear.compose:compose-navigation:...")

Tambahkan:

implementation("androidx.navigation3:navigation3-runtime:...") // State logic
implementation("androidx.navigation3:navigation3-ui:...")      // Display logic
implementation("androidx.wear.compose:compose-navigation3:...") // Wear gestures
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:...") // Requires compiler plugin

2. Memperbarui tujuan untuk menerapkan NavKey

Di Navigation 2, Anda mungkin telah menggunakan string atau objek generik untuk perutean. Di Navigation 3, Anda harus menerapkan antarmuka penanda NavKey dan menganotasi setiap objek layar dengan @Serializable.

Mengapa ini diperlukan? Untuk menjamin bahwa data sebelumnya dapat disimpan dan dipulihkan saat proses dihentikan, navigation3-runtime yang mendasarinya mengandalkan kotlinx-serialization untuk melakukan serialisasi status.

Sebelumnya (Navigation 2 - Rute Umum yang Aman untuk Jenis):

sealed class Nav2Screen {
    data object Landing : Nav2Screen()
    data object List : Nav2Screen()
}

Setelah (Navigation 3 - NavKey + Serializable):

@Serializable
sealed interface MigrationScreen : NavKey {
    @Serializable
    data object Landing : MigrationScreen

    @Serializable
    data object List : MigrationScreen
}

3. Mengganti Logika Pemilihan Rute (NavController menjadi NavBackStack)

Ganti NavController Anda dengan NavBackStack yang diinisialisasi melalui rememberNavBackStack. Anda juga perlu membuat instance SwipeDismissableSceneStrategy khusus untuk Wear OS.

Sebelum (Navigasi 2):

val navController = rememberSwipeDismissableNavController()

Setelah (Navigasi 3):

val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey)
val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()

4. Mengganti NavHost dengan NavDisplay dan DSL entryProvider

Penampung NavHost dan DSL builder composable("route") { ... } internalnya digantikan oleh NavDisplay dan DSL { entry<Key> { ... } } entryProvider.

Sebelum (Navigasi 2):

SwipeDismissableNavHost(navController = navController, startDestination = "menu") {
    composable("menu") {
        GreetingScreen(
            onShowList = { navController.navigate("list") }
        )
    }
    composable("list") {
        ListScreen()
    }
}

Setelah (Navigasi 3):

NavDisplay(
    backStack = backStack,
    sceneStrategies = listOf(strategy),
    entryProvider = entryProvider {
        entry<MigrationScreen.Landing> {
            GreetingScreen(
                onShowList = { backStack.add(MigrationScreen.List) }
            )
        }
        entry<MigrationScreen.List> {
            ListScreen()
        }
    }
)