Menyimpan dan mengelola status navigasi

Bagian berikut menjelaskan strategi untuk menyimpan data sebelumnya dan menyimpan status yang terkait dengan entri di data sebelumnya.

Menyimpan data sebelumnya

Memastikan status navigasi aplikasi Anda tetap ada di berbagai peristiwa siklus proses, termasuk perubahan konfigurasi dan penghentian proses, sangat penting untuk pengalaman pengguna yang baik. Di Navigation 3, Anda memiliki data sebelumnya, sehingga tidak ada panduan ketat tentang cara membuat atau menyimpannya. Namun, Navigation 3 menawarkan metode praktis yang memberi Anda data sebelumnya yang dapat disimpan: rememberNavBackStack.

Gunakan rememberNavBackStack

Fungsi composable rememberNavBackStack dirancang untuk membuat data sebelumnya yang tetap ada di seluruh perubahan konfigurasi dan penghentian proses.

Agar rememberNavBackStack berfungsi dengan benar, setiap kunci dalam data sebelumnya harus mematuhi persyaratan tertentu:

  • Mengimplementasikan antarmuka NavKey: Setiap kunci dalam data sebelumnya harus mengimplementasikan antarmuka NavKey. Ini berfungsi sebagai antarmuka penanda yang memberi sinyal kepada library bahwa kunci dapat disimpan.
  • Memiliki anotasi @Serializable: Selain mengimplementasikan NavKey, class dan objek kunci Anda harus ditandai dengan anotasi @Serializable.

Cuplikan berikut menunjukkan penerapan rememberNavBackStack yang benar:

@Serializable
data object Home : NavKey

@Composable
fun NavBackStack() {
    val backStack = rememberNavBackStack(Home)
}

Mengingat data sebelumnya dengan subjenis NavKey

Fungsi composable rememberNavBackStack menampilkan NavBackStack<NavKey>. Jika aplikasi Anda menentukan subjenis NavKey-nya sendiri yang diwarisi oleh semua kuncinya, Anda dapat mempertahankan pengetikan tersebut dengan menerapkan fungsi remember kustom, seperti berikut:

@Serializable
sealed interface MyAppNavKey : NavKey

@Serializable
data object ScreenA: MyAppNavKey

@Serializable
data class ScreenB(val id: String): MyAppNavKey

@Composable
fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> {
    return rememberSerializable(serializer = serializer()) {
        NavBackStack(*elements)
    }
}

@Composable
fun MyApp() {
    // defaultNavBackStack is NavBackStack<NavKey>
    val defaultNavBackStack = rememberNavBackStack(ScreenA)
    // myAppNavBackStack is NavBackStack<MyAppNavKey>
    val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA)
}

Untuk contoh lainnya—termasuk cara menangani polimorfisme terbuka—lihat NavBackStackSamples.

Alternatif: Menyimpan di ViewModel

Pendekatan lain untuk mengelola data sebelumnya adalah dengan menyimpannya di ViewModel. Untuk persistensi melalui penghentian proses saat menggunakan ViewModel atau penyimpanan kustom lainnya, Anda perlu:

  • Pastikan kunci Anda dapat diserialisasi: Sama seperti rememberNavBackStack, kunci navigasi Anda harus dapat diserialisasi.
  • Menangani serialisasi dan deserialisasi secara manual: Anda bertanggung jawab untuk menyimpan representasi serial setiap kunci secara manual ke, dan mendeserialisasinya dari, penyimpanan persisten (misalnya, SharedPreferences, database, atau file) saat aplikasi Anda beralih ke latar belakang atau sedang dipulihkan.

Mencakup instance ViewModel ke objek NavEntry

ViewModels digunakan untuk mempertahankan status terkait UI saat terjadi perubahan konfigurasi, seperti rotasi layar. Secara default, ViewModels dicakup ke ViewModelStoreOwner terdekat, yang biasanya merupakan Activity atau Fragment Anda.

Namun, Anda mungkin ingin mencakupkan ViewModel ke NavEntry tertentu (yaitu, layar atau tujuan tertentu) di data sebelumnya, bukan seluruh Activity. Hal ini memastikan bahwa status ViewModel hanya dipertahankan saat NavEntry tertentu tersebut adalah bagian dari data sebelumnya, dan dihapus saat NavEntry muncul.

Library add-on androidx.lifecycle:lifecycle-viewmodel-navigation3 menyediakan NavEntryDecorator yang memfasilitasi hal ini. Dekorator ini menyediakan ViewModelStoreOwner untuk setiap NavEntry. Saat Anda membuat ViewModel di dalam konten NavEntry (misalnya, menggunakan viewModel() di Compose), cakupannya akan otomatis dibatasi ke kunci NavEntry tertentu di data sebelumnya. Artinya, ViewModel dibuat saat NavEntry ditambahkan ke data sebelumnya, dan dihapus saat dihapus.

Untuk menggunakan NavEntryDecorator guna mencakup ViewModel ke NavEntry, ikuti langkah-langkah berikut:

  1. Tambahkan dependensi androidx.lifecycle:lifecycle-viewmodel-navigation3 ke file app/build.gradle.kts Anda.
  2. Tambahkan rememberSaveableStateHolderNavEntryDecorator() default ke daftar entryDecorators saat membuat NavDisplay.
  3. Tambahkan rememberViewModelStoreNavEntryDecorator() ke daftar entryDecorators.

NavDisplay(
    entryDecorators = listOf(
        // Add the default decorators for managing scenes and saving state
        rememberSaveableStateHolderNavEntryDecorator(),
        // Then add the view model store decorator
        rememberViewModelStoreNavEntryDecorator()
    ),
    backStack = backStack,
    entryProvider = entryProvider { },
)