Bermigrasi ke Navigation 3

Navigation 3 mewakili 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 Langsung Back Stack: NavBackStack pada dasarnya hanyalah daftar objek NavKey yang dapat diubah, yang mewakili histori layar yang telah dikunjungi pengguna. Anda mengontrolnya persis seperti Kotlin MutableList (add, removeLast, clear). Anda langsung memanipulasi daftar untuk melakukan tindakan navigasi, seperti menambahkan kunci untuk maju atau menghapus kunci untuk kembali.
  • Desain Compose-First: Back stack dimodelkan sebagai status yang dapat diamati standar standar. Mengubah histori navigasi Anda berperilaku persis seperti memperbarui status Compose lainnya, yang secara otomatis memicu rekomposisi untuk menampilkan layar saat ini.
  • Type-Safe secara Default: Rute berbasis string dihilangkan sepenuhnya. Navigation menggunakan objek data dan class data yang dapat diserialisasi.
  • Presentasi yang Dipisahkan (Strategi Scene): 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 terpisah yang baru, beserta dukungan serialisasi Kotlin.

Hapus:

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

Menambahkan:

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 perlu? Agar back stack dapat disimpan dan dipulihkan di seluruh penghentian proses, navigation3-runtime yang mendasarinya bergantung pada kotlinx-serialization untuk melakukan serialisasi status.

Sebelum (Navigation 2 - Rute Type-Safe Generik):

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 Perutean (NavController ke NavBackStack)

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

Sebelum (Navigation 2):

val navController = rememberSwipeDismissableNavController()

Setelah (Navigation 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 diganti dengan NavDisplay dan DSL entryProvider { entry<Key> { ... } }.

Sebelum (Navigation 2):

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

Setelah (Navigation 3):

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