Navigasi dan data sebelumnya

NavController menyimpan "data sebelumnya" yang berisi tujuan pengguna telah dikunjungi. Saat pengguna bernavigasi di dalam aplikasi Anda, NavController menambah dan menghapus tujuan ke dan dari data sebelumnya.

Dalam stack, data sebelumnya adalah struktur data "masuk terakhir, keluar pertama". Tujuan Oleh karena itu, NavController mendorong item ke dan memunculkan item dari bagian atas {i>stack<i}.

Perilaku dasar

Berikut ini fakta inti yang harus Anda pertimbangkan terkait perilaku data sebelumnya:

  • Tujuan pertama: Saat pengguna membuka aplikasi, NavController mendorong tujuan pertama ke bagian atas data sebelumnya.
  • Mendorong ke stack: Setiap panggilan NavController.navigate() mendorong tujuan yang diberikan ke bagian atas stack.
  • Memunculkan tujuan teratas: Mengetuk Up atau Back akan memanggil NavController.navigateUp() dan NavController.popBackStack(). Metode tersebut memunculkan tujuan teratas dari stack. Lihat halaman Prinsip Navigasi untuk mengetahui informasi selengkapnya tentang perbedaan antara Up dan Back.

Mengembalikan

Metode NavController.popBackStack() mencoba memunculkan tujuan saat ini dari data sebelumnya dan menavigasi ke tujuan sebelumnya. Metode ini secara efektif mengembalikan pengguna ke satu langkah sebelumnya di histori navigasi. Metode ini menampilkan boolean yang menunjukkan apakah metode tersebut berhasil kembali ke tujuan.

Mengembalikan ke tujuan tertentu

Anda juga dapat menggunakan popBackStack() untuk menavigasi ke tujuan tertentu. Untuk melakukannya, gunakan salah satu overload. Ada beberapa overload yang memungkinkan Anda meneruskan ID, seperti bilangan bulat id atau string route. Overload ini membawa pengguna ke tujuan yang terkait dengan ID yang diberikan. Yang terpenting, overload tersebut mengembalikan semua tumpukan di atas tujuan tersebut.

Overload ini juga menggunakan boolean inclusive. Boolean menentukan apakah NavController juga harus memunculkan tujuan yang ditentukan dari data sebelumnya setelah menavigasi ke tujuan tersebut.

Perhatikan cuplikan singkat ini sebagai contoh:

navController.popBackStack(R.id.destinationId, true)

Di sini, NavController kembali ke tujuan dengan ID bilangan bulat destinationId. Karena nilai argumen inclusive adalah true, NavController juga memunculkan tujuan yang ditentukan dari data sebelumnya.

Menangani pengembalian yang gagal

Saat popBackStack() menampilkan false, panggilan berikutnya ke NavController.getCurrentDestination() akan menampilkan null. Hal ini berarti aplikasi telah kembali ke tujuan terakhir dari data sebelumnya. Dalam hal ini, pengguna hanya melihat layar kosong.

Hal ini dapat terjadi dalam kasus berikut:

  • popBackStack() tidak memunculkan apa pun dari stack.
  • popBackStack() memunculkan tujuan dari data sebelumnya dan stack sekarang kosong.

Untuk mengatasi hal ini, Anda harus menavigasi ke tujuan baru atau memanggil finish() pada aktivitas untuk mengakhirinya. Cuplikan berikut menunjukkan hal tersebut:

kotlin

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish()
}

java

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish();
}

Memunculkan ke tujuan

Untuk menghapus tujuan dari data sebelumnya saat menavigasi dari satu tujuan ke tujuan lain, tambahkan argumen popUpTo() ke panggilan fungsi navigate() terkait. popUpTo() menginstruksikan library Navigasi untuk menghapus beberapa tujuan dari data sebelumnya sebagai bagian dari panggilan ke navigate(). Nilai parameter adalah ID tujuan di data sebelumnya. ID dapat berupa bilangan bulat id atau string route.

Anda dapat menyertakan argumen untuk parameter inclusive dengan nilai true untuk menunjukkan bahwa tujuan yang telah Anda tentukan di popUpTo() juga harus muncul dari data sebelumnya.

Untuk menerapkan hal ini secara terprogram, teruskan popUpTo() ke navigate() sebagai bagian dari NavOptions dengan inclusive ditetapkan ke true. Tindakan ini berfungsi di Compose dan View.

Menyimpan status saat memunculkan

Saat menggunakan popUpTo untuk menavigasi ke tujuan, Anda dapat menyimpan data sebelumnya dan status semua tujuan muncul dari data sebelumnya. Anda dapat kemudian memulihkan data sebelumnya dan tujuan saat menavigasi ke tujuan tersebut di lain waktu. Hal ini memungkinkan Anda mempertahankan status untuk tujuan tertentu dan memiliki beberapa data sebelumnya.

Untuk melakukannya secara terprogram, tentukan saveState = true saat menambahkan popUpTo ke opsi navigasi Anda.

Anda juga dapat menentukan restoreState = true di opsi navigasi untuk secara otomatis memulihkan data sebelumnya dan status yang terkait dengan tujuan.

Contoh:

navController.navigate(
    route = route,
    navOptions =  navOptions {
        popUpTo<A>{ saveState = true }
        restoreState = true
    }
)

Untuk mengaktifkan penyimpanan dan pemulihan status dalam XML, tentukan popUpToSaveState sebagai true dan restoreState sebagai true masing-masing dalam action terkait.

Contoh XML

Berikut adalah contoh popUpTo di XML, menggunakan tindakan:

<action
  android:id="@+id/action_a_to_b"
  app:destination="@id/b"
  app:popUpTo="@+id/a"
  app:popUpToInclusive="true"
  app:restoreState=”true”
  app:popUpToSaveState="true"/>

Contoh Compose

Berikut adalah contoh lengkap yang sama di Compose:

@Composable
fun MyAppNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(),
    startDestination: Any = A
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        composable<A> {
            DestinationA(
                onNavigateToB = {
                // Pop everything up to, and including, the A destination off
                // the back stack, saving the back stack and the state of its
                // destinations.
                // Then restore any previous back stack state associated with
                // the B destination.
                // Finally navigate to the B destination.
                    navController.navigate(route = B) {
                        popUpTo<A> {
                            inclusive = true
                            saveState = true
                        }
                        restoreState = true
                    }
                },
            )
        }
        composable<B> { DestinationB(/* ... */) }
    }
}

@Composable
fun DestinationA(onNavigateToB: () -> Unit) {
    Button(onClick = onNavigateToB) {
        Text("Go to A")
    }
}

Secara lebih terperinci, Anda dapat mengubah cara memanggil NavController.navigate() dengan cara berikut:

// Pop everything up to the destination_a destination off the back stack before
// navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a")
}

// Pop everything up to and including the "destination_a" destination off
// the back stack before navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a") { inclusive = true }
}

// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
    launchSingleTop = true
}

Untuk informasi umum tentang cara meneruskan opsi ke NavController.navigate(), lihat panduan Menavigasi dengan opsi.

Memunculkan menggunakan tindakan

Saat menavigasi menggunakan tindakan, Anda dapat memunculkan tujuan tambahan secara opsional dari data sebelumnya. Misalnya, jika aplikasi Anda memiliki alur login awal, saat pengguna login, Anda harus memunculkan semua tujuan yang terkait login dari data sebelumnya sehingga tombol Kembali tidak mengembalikan pengguna ke alur login.

Bacaan tambahan

Untuk informasi lebih lanjut, lihat halaman berikut:

  • Navigasi melingkar: Pelajari cara menghindari data sebelumnya yang terlalu sesak jika alur navigasi berbentuk lingkaran.
  • Tujuan dialog: Baca tentang bagaimana tujuan dialog memberikan pertimbangan unik tentang cara Anda mengelola data sebelumnya.