API Cakupan ViewModel   Bagian dari Android Jetpack.

Cakupan adalah kunci untuk menggunakan ViewModel secara efektif. Setiap ViewModel dicakup ke objek yang menerapkan antarmuka ViewModelStoreOwner. Ada beberapa API yang memungkinkan Anda mengelola cakupan ViewModel dengan lebih mudah. Dokumen ini menguraikan beberapa teknik utama yang harus Anda ketahui.

Metode ViewModelProvider.get() memungkinkan Anda mendapatkan instance ViewModel yang dicakupkan ke ViewModelStoreOwner apa pun. Untuk pengguna Kotlin, terdapat berbagai fungsi ekstensi yang tersedia untuk kasus penggunaan paling umum. Semua penerapan fungsi ekstensi Kotlin menggunakan ViewModelProvider API di balik layar.

ViewModel yang dicakupkan ke ViewModelStoreOwner terdekat

Anda dapat menentukan cakupan ViewModel ke composable, Activity, atau tujuan grafik Navigation. Fungsi viewModel() di Compose memungkinkan Anda mendapatkan instance ViewModel yang dicakupkan ke ViewModelStoreOwner terdekat.

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    // ViewModel API available in lifecycle.lifecycle-viewmodel-compose
    // The ViewModel is scoped to the closest ViewModelStoreOwner provided
    // via the LocalViewModelStoreOwner CompositionLocal. In order of proximity,
    // this could be the destination of a Navigation graph
    // or the host Activity.
    viewModel: MyViewModel = viewModel()
) { /* ... */ }

ViewModel yang dicakupkan ke ViewModelStoreOwner apa pun

Fungsi viewModel() mengambil parameter viewModelStoreOwner opsional yang dapat Anda gunakan untuk menentukan ViewModelStoreOwner mana yang dicakupkan ke instance ViewModel.

import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.lifecycle.ViewModelStoreOwner

@Composable
fun MyScreen(
    // A custom owner passed in, such as a parent NavBackStackEntry
    customOwner: ViewModelStoreOwner,
    // The ViewModel is now scoped to the provided customOwner
    viewModel: MyViewModel = viewModel(viewModelStoreOwner = customOwner)
) {
    /* ... */
}

ViewModel yang dicakupkan ke composable

Anda dapat menggunakan rememberViewModelStoreOwner() untuk mencakup ViewModel langsung ke situs panggilan composable. Hal ini sangat berguna untuk komponen UI yang ditambahkan atau dihapus secara dinamis dari layar berdasarkan status, seperti item halaman atau daftar lambat. Saat composable yang memiliki ViewModelStoreOwner meninggalkan komposisi, ViewModelStore terkait akan dihapus dan ViewModel akan dihancurkan.

Gunakan rememberViewModelStoreOwner() untuk membuat penyimpanan yang mendukung siklus proses dan dipertahankan meskipun konfigurasi diubah.

@Composable
fun RememberViewModelStoreOwnerSample() {
    // Create a ViewModelStoreOwner scoped to this specific call site.
    // When this composable leaves the composition,
    // the associated ViewModelStore will be cleared.
    val scopedOwner = rememberViewModelStoreOwner()

    CompositionLocalProvider(LocalViewModelStoreOwner provides scopedOwner) {
        // This ViewModel is scoped to `scopedOwner`.
        // It will survive configuration changes but will be cleared when
        // the composable is removed from the UI tree.
        val viewModel = viewModel { TestViewModel("scoped_data") }
        // Use the ViewModel
    }
}

Untuk penerapan yang lebih kompleks, seperti HorizontalPager atau kasus yang memerlukan beberapa cakupan independen, gunakan rememberViewModelStoreProvider(). Hal ini memungkinkan Anda membuat instance ViewModelStoreOwner yang berbeda untuk kunci yang berbeda (seperti indeks halaman). Dengan cara ini, setiap halaman mempertahankan status ViewModel independennya sendiri.

@Composable
fun RememberViewModelStoreProviderSample() {
    val storeProvider = rememberViewModelStoreProvider()
    val pages = listOf("Page 1", "Page 2", "Page 3")

    HorizontalPager(pageCount = pages.size) { page ->
        // Create a ViewModelStoreOwner for the specific page using the provider.
        val pageOwner = rememberViewModelStoreOwner(provider = storeProvider, key = page)

        CompositionLocalProvider(LocalViewModelStoreOwner provides pageOwner) {
            val pageViewModel = viewModel { TestViewModel(pages[page]) }
            // Use pageViewModel
        }
    }
}

ViewModel yang dicakupkan ke grafik Navigation

Grafik Navigation juga merupakan pemilik penyimpanan ViewModel. Jika menggunakan Navigation Compose, Anda bisa mendapatkan instance ViewModel yang dicakupkan ke grafik Navigation dengan fungsi getBackStackEntry().

viewModel() mengambil instance dari ViewModelStoreOwner yang disediakan oleh LocalViewModelStoreOwner CompositionLocal. Dalam aplikasi Compose umum yang menggunakan Jetpack Navigation, pemilik ini adalah entri back stack Navigation saat ini. Artinya, ViewModel tetap berada dalam memori selama tujuan tersebut ada di back stack.

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyAppNavHost() {
    // ...
    composable("myScreen") { backStackEntry ->
        // Retrieve the NavBackStackEntry of "parentNavigationRoute"
        val parentEntry = remember(backStackEntry) {
            navController.getBackStackEntry("parentNavigationRoute")
        }
        // Get the ViewModel scoped to the `parentNavigationRoute` Nav graph
        val parentViewModel: SharedViewModel = viewModel(parentEntry)
        // ...
    }
}

Jika menggunakan Hilt sebagai tambahan Jetpack Navigation, Anda dapat menggunakan hiltNavGraphViewModels(graphId) API sebagai berikut.

import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun MyAppNavHost() {
    // ...
    composable("myScreen") { backStackEntry ->
        val parentEntry = remember(backStackEntry) {
            navController.getBackStackEntry("parentNavigationRoute")
        }

        // ViewModel API available in hilt.hilt-navigation-compose
        // The ViewModel is scoped to the `parentNavigationRoute` Navigation graph
        // and is provided using the Hilt-generated ViewModel factory
        val parentViewModel: SharedViewModel = hiltViewModel(parentEntry)
        // ...
    }
}

Referensi lainnya

Untuk mempelajari ViewModel dan cakupan lebih lanjut, lihat referensi tambahan berikut:

Dokumentasi

Konten View