Memigrasikan Jetpack Navigation ke Navigation Compose

Navigation Compose API memungkinkan Anda menavigasi antar-composable dalam Aplikasi Compose, sambil memanfaatkan komponen Jetpack Navigation, infrastruktur, dan fitur.

Halaman ini menjelaskan cara melakukan migrasi dari Jetpack Navigation berbasis Fragmen ke Navigation Compose, sebagai bagian dari migrasi UI berbasis View yang lebih besar ke Jetpack Tulis.

Prasyarat migrasi

Anda dapat bermigrasi ke Navigation Compose setelah dapat mengganti semua Fragmen dengan composable layar yang sesuai. Composable layar dapat berisi campuran konten Compose dan View, tetapi semua tujuan navigasi harus composable untuk mengaktifkan migrasi Navigation Compose. Sebelum itu, Anda seharusnya terus menggunakan komponen Navigasi Berbasis Fragmen dalam Tampilan interop Anda dan Codebase Compose. Lihat dokumentasi interop navigasi untuk informasi selengkapnya tidak akurat atau tidak sesuai.

Menggunakan Navigation Compose di aplikasi khusus Compose bukan prasyarat. Anda dapat terus menggunakan komponen Navigasi berbasis Fragmen, selama Anda tetap Fragmen untuk menghosting konten composable.

Langkah migrasi

Apakah Anda mengikuti strategi migrasi yang kami rekomendasikan atau mengambil pendekatan lain, Anda akan mencapai titik di mana semua tujuan navigasi composable layar, dengan Fragment bertindak hanya sebagai penampung composable. Di Anda dapat bermigrasi ke Navigation Compose.

Jika aplikasi Anda sudah mengikuti pola desain UDF dan panduan untuk arsitektur, migrasi ke Jetpack Compose dan Navigation Compose tidak boleh memerlukan pemfaktoran ulang utama lapisan lain aplikasi Anda, selain lapisan UI.

Untuk bermigrasi ke Navigation Compose, ikuti langkah-langkah berikut:

  1. Tambahkan dependensi Navigation Compose ke aplikasi Anda.
  2. Buat composable App-level dan tambahkan ke Activity sebagai Titik entri Compose, yang menggantikan penyiapan tata letak View:

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

  3. Membuat jenis untuk setiap tujuan navigasi. Gunakan data object untuk tujuan yang tidak memerlukan data apa pun dan data class atau class untuk tujuan yang memerlukan data.

    @Serializable data object First
    @Serializable data class Second(val id: String)
    @Serializable data object Third
    

  4. Menyiapkan NavController di tempat semua composable yang memerlukan untuk mereferensikannya, file tersebut dapat mengaksesnya (biasanya ada di dalam App composable). Pendekatan ini mengikuti prinsip pengangkatan status dan memungkinkan Anda menggunakan NavController sebagai sumber kebenaran untuk menavigasi antar-layar composable dan mengelola data sebelumnya:

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

  5. Buat NavHost aplikasi Anda di dalam composable App dan teruskan navController:

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

  6. Tambahkan tujuan composable untuk membuat grafik navigasi. Jika setiap sebelumnya telah dimigrasikan ke Compose, langkah ini hanya terdiri dari mengekstrak composable layar ini dari Fragment ke dalam composable tujuan:

    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(/* ... */)
            }
            // ...
        }
    }

  7. Jika Anda mengikuti panduan tentang merancang UI Compose, khususnya cara penerusan ViewModel dan peristiwa navigasi ke composable, langkah berikutnya adalah mengubah cara menyediakan ViewModel untuk setiap composable layar. Anda dapat sering menggunakan injeksi Hilt dan integrasinya dengan Compose dan Navigation melalui hiltViewModel:

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

  8. Ganti semua panggilan navigasi findNavController() dengan navController dan meneruskannya sebagai peristiwa navigasi ke setiap layar composable, bukan daripada meneruskan seluruh navController. Pendekatan ini mengikuti cara terbaik praktik mengekspos peristiwa dari fungsi composable ke pemanggil dan mempertahankan navController sebagai satu-satunya sumber kebenaran.

    Data dapat diteruskan ke tujuan dengan membuat instance rute yang ditentukan untuk tujuan tersebut. Data ini kemudian dapat diperoleh secara langsung dari entri data sebelumnya di tujuan atau dari ViewModel menggunakan SavedStateHandle.toRoute().

    @Composable
    fun SampleNavHost(
        navController: NavHostController
    ) {
        NavHost(navController = navController, startDestination = First) {
            composable<First> {
                FirstScreen(
                    onButtonClick = {
                        // findNavController().navigate(firstScreenToSecondScreenAction)
                        navController.navigate(Second(id = "ABC"))
                    }
                )
            }
            composable<Second> { backStackEntry ->
                val secondRoute = backStackEntry.toRoute<Second>()
                SecondScreen(
                    id = secondRoute.id,
                    onIconClick = {
                        // findNavController().navigate(secondScreenToThirdScreenAction)
                        navController.navigate(Third)
                    }
                )
            }
            // ...
        }
    }

  9. Hapus semua Fragment, tata letak XML yang relevan, navigasi yang tidak perlu, dan resource, dan dependensi Jetpack Navigation yang sudah tidak berlaku.

Anda dapat menemukan langkah-langkah yang sama dengan detail terkait Navigation Compose lainnya di Dokumentasi penyiapan.

Kasus penggunaan umum

Apa pun komponen Navigasi yang Anda gunakan, prinsip yang sama navigasi akan diterapkan.

Kasus penggunaan umum saat melakukan migrasi mencakup hal berikut:

Untuk informasi lebih detail tentang kasus penggunaan ini, lihat Menavigasi dengan Tulis.

Mengambil data yang kompleks saat menavigasi

Kami sangat menyarankan untuk tidak meneruskan objek data yang kompleks saat bernavigasi. Sebagai gantinya, teruskan informasi minimum yang diperlukan, seperti ID unik atau bentuk ID lain, sebagai argumen saat melakukan tindakan navigasi. Anda seharusnya menyimpan objek yang kompleks sebagai data dalam satu sumber yang terpercaya, seperti data . Untuk informasi selengkapnya, lihat Mengambil data kompleks saat menavigasi.

Jika Fragment Anda meneruskan objek kompleks sebagai argumen, pertimbangkan pemfaktoran ulang kode Anda terlebih dahulu, dengan cara yang memungkinkan penyimpanan dan pengambilan objek ini dari lapisan data. Lihat Repositori Now in Android untuk contoh.

Batasan

Bagian ini menjelaskan batasan saat ini untuk Navigation Compose.

Migrasi inkremental ke Navigation Compose

Saat ini, Anda tidak dapat menggunakan Navigation Compose saat masih menggunakan Fragment sebagai tujuan dalam kode Anda. Untuk mulai menggunakan Navigation Compose, semua tujuan harus berupa composable. Anda dapat melacak permintaan fitur ini di Issue Tracker.

Animasi transisi

Dimulai dengan Navigation 2.7.0-alpha01, dukungan untuk setelan kustom transisi, sebelumnya dari AnimatedNavHost, kini menjadi didukung secara langsung di NavHost. Baca catatan rilis untuk informasi selengkapnya.

Pelajari lebih lanjut

Untuk informasi selengkapnya tentang cara bermigrasi ke Navigation Compose, lihat referensi berikut referensi:

  • Codelab Navigation Compose: Mempelajari dasar-dasar Navigation Compose dengan codelab langsung.
  • Now in Android repository: Aplikasi Android yang berfungsi penuh sepenuhnya dibangun dengan Kotlin dan Jetpack Compose, yang mengikuti desain Android dan praktik terbaik pengembangan, serta menyertakan Navigation Compose.
  • Memigrasikan Sunflower ke Jetpack Compose: Postingan blog yang mendokumentasikan perjalanan migrasi aplikasi contoh Sunflower dari View ke Compose, yang juga mencakup migrasi ke Navigation Compose.
  • Jetnews untuk setiap layar: Postingan blog yang mendokumentasikan pemfaktoran ulang dan migrasi contoh Jetnews untuk mendukung semua layar dengan Jetpack Compose dan Navigation Compose.