Ringkasan ViewModel Bagian dari Android Jetpack.
Class ViewModel adalah pemegang logika bisnis atau holder status tingkat
layar. Class ini mengekspos status ke UI dan mengenkapsulasi logika bisnis terkait.
Keuntungan utamanya adalah melakukan cache status dan mempertahankannya melalui
perubahan konfigurasi. Artinya, UI Anda tidak perlu mengambil data lagi
saat bernavigasi di antara aktivitas, atau mengikuti perubahan konfigurasi, seperti
saat memutar layar.
Untuk informasi selengkapnya tentang holder status, lihat panduan holder status. Demikian pula, untuk mengetahui informasi selengkapnya tentang lapisan UI secara umum, lihat panduan lapisan UI.
Manfaat ViewModel
Alternatif untuk ViewModel adalah class biasa yang menyimpan data yang ditampilkan di UI. Hal ini dapat menjadi masalah saat bernavigasi di antara aktivitas atau tujuan Navigation. Tindakan ini akan menghapus data tersebut jika Anda tidak menyimpannya menggunakan mekanisme status instance tersimpan. ViewModel menyediakan API yang praktis untuk persistensi data yang menyelesaikan masalah ini.
Atau, untuk penampung status murni, Compose menawarkan kemampuan retain yang memungkinkan class biasa bertahan saat terjadi perubahan konfigurasi tanpa infrastruktur lengkap ViewModel. Meskipun kedua mekanisme membantu mempertahankan status,
umumnya lebih aman untuk menyediakan ViewModel ke instance yang dipertahankan daripada
sebaliknya, karena siklus proses dan perilaku pembersihan keduanya berbeda.
Manfaat utama class ViewModel pada dasarnya ada dua:
- Memungkinkan Anda mempertahankan status UI.
- Menyediakan akses ke logika bisnis.
Persistensi
ViewModel memungkinkan persistensi melalui status yang dimiliki ViewModel, dan operasi yang dipicu ViewModel. Cache ini berarti Anda tidak perlu mengambil data lagi melalui perubahan konfigurasi umum, seperti rotasi layar.
Cakupan
Saat membuat instance ViewModel, Anda akan meneruskan objek yang mengimplementasikan
antarmuka ViewModelStoreOwner. Ini dapat berupa tujuan Navigation,
grafik Navigation, aktivitas, atau jenis lain yang mengimplementasikan
antarmuka. Anda juga dapat mencakup ViewModel langsung ke composable menggunakan
rememberViewModelStoreOwner API.
ViewModel Anda kemudian tercakup ke Lifecycle
ViewModelStoreOwner. ViewModel tetap ada dalam memori hingga ViewModelStoreOwner-nya
hilang secara permanen (seperti saat pemilik komponen keluar dari Komposisi).
Rentang class adalah subclass langsung atau tidak langsung dari
antarmuka ViewModelStoreOwner. Subclass langsung adalah
ComponentActivity dan NavBackStackEntry.
Untuk mengetahui daftar lengkap subclass tidak langsung, lihat
referensi ViewModelStoreOwner. Untuk mencakup ViewModels ke setiap item
dalam LazyList atau Pager, gunakan rememberViewModelStoreProvider() untuk mengangkat
pengelolaan pemilik ke induk.
Saat aktivitas host mengalami perubahan konfigurasi, pekerjaan asinkron akan berlanjut di ViewModel, baik yang dicakup ke aktivitas maupun ke composable tertentu. Inilah kunci untuk persistensi.
Untuk informasi selengkapnya, lihat bagian siklus proses ViewModel di bawah, API Cakupan ViewModel, dan panduan tentang pengangkatan status untuk Jetpack Compose.
SavedStateHandle
SavedStateHandle memungkinkan Anda mempertahankan data tidak hanya melalui perubahan konfigurasi, tetapi juga seluruh penghentian proses. Artinya, hal ini memungkinkan Anda untuk menjaga status UI tetap utuh bahkan ketika pengguna menutup aplikasi dan membukanya di lain waktu.
Untuk mengetahui informasi selengkapnya tentang menyimpan status UI, lihat Menyimpan status UI di Compose.
Akses ke logika bisnis
Meskipun sebagian besar logika bisnis ada di lapisan data, lapisan UI juga dapat berisi logika bisnis. Hal ini dapat terjadi saat menggabungkan data dari beberapa repositori untuk membuat status UI layar, atau saat jenis data tertentu tidak memerlukan lapisan data.
ViewModel adalah tempat yang tepat untuk menangani logika bisnis di lapisan UI. ViewModel juga bertanggung jawab menangani peristiwa dan mendelegasikannya ke lapisan hierarki lain saat logika bisnis perlu diterapkan untuk mengubah data aplikasi.
Mengimplementasikan ViewModel
Berikut adalah contoh implementasi ViewModel untuk layar yang memungkinkan pengguna melempar dadu.
data class DiceUiState(
val firstDieValue: Int? = null,
val secondDieValue: Int? = null,
val numberOfRolls: Int = 0,
)
class DiceRollViewModel : ViewModel() {
// Expose screen UI state
private val _uiState = MutableStateFlow(DiceUiState())
val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()
// Handle business logic
fun rollDice() {
_uiState.update { currentState ->
currentState.copy(
firstDieValue = Random.nextInt(from = 1, until = 7),
secondDieValue = Random.nextInt(from = 1, until = 7),
numberOfRolls = currentState.numberOfRolls + 1,
)
}
}
}
Anda kemudian dapat mengakses ViewModel dari composable tingkat layar dengan cara sebagai berikut:
import androidx.lifecycle.viewmodel.compose.viewModel
// Use the 'viewModel()' function from the lifecycle-viewmodel-compose artifact
@Composable
fun DiceRollScreen(
viewModel: DiceRollViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
// Update UI elements
}
Menggunakan coroutine dengan ViewModel
ViewModel mencakup dukungan untuk coroutine Kotlin. API ini dapat mempertahankan
pekerjaan asinkron dengan cara yang sama seperti mempertahankan status UI.
Untuk informasi selengkapnya, lihat Menggunakan coroutine Kotlin dengan Komponen Arsitektur Android.
Siklus proses ViewModel
Siklus proses ViewModel terikat langsung dengan cakupannya. ViewModel
tetap berada dalam memori sampai ViewModelStoreOwner yang dicakupnya
menghilang. Hal ini dapat terjadi dalam konteks berikut:
- Dalam kasus aktivitas, setelah aktivitas selesai.
- Dalam kasus entri Navigation, saat entri tersebut dihapus dari data sebelumnya.
- Dalam kasus composable, saat composable keluar dari Komposisi.
Anda dapat menggunakan
rememberViewModelStoreOwneruntuk mencakup ViewModel secara langsung ke bagian UI yang arbitrer (sepertiPageratauLazyList).
Hal ini membuat ViewModel menjadi solusi yang bagus untuk menyimpan data yang bertahan dari perubahan konfigurasi.
Gambar 1 menunjukkan berbagai status siklus proses suatu aktivitas saat aktivitas tersebut mengalami
rotasi dan kemudian selesai. Gambar ini juga menunjukkan masa aktif
ViewModel di sebelah siklus proses aktivitas yang terkait. Diagram khusus
ini menggambarkan status suatu aktivitas.
Anda biasanya meminta ViewModel saat sistem pertama kali memanggil
metode onCreate() milik objek aktivitas. Sistem mungkin memanggil
onCreate() beberapa kali selama masa aktif aktivitas, seperti
saat layar perangkat diputar. ViewModel tersedia sejak saat Anda pertama kali
meminta ViewModel sampai aktivitas selesai dan dihancurkan.
Menghapus dependensi ViewModel
ViewModel memanggil metode onCleared saat ViewModelStoreOwner
menghancurkannya selama siklus prosesnya. Hal ini memungkinkan Anda untuk membersihkan pekerjaan
atau dependensi yang mengikuti siklus proses ViewModel.
Contoh berikut menunjukkan alternatif untuk viewModelScope.
viewModelScope adalah CoroutineScope bawaan yang
otomatis mengikuti siklus proses ViewModel. ViewModel menggunakannya untuk
memicu operasi terkait bisnis. Jika Anda ingin menggunakan cakupan kustom, bukan
viewModelScope untuk pengujian yang lebih mudah, ViewModel dapat menerima
CoroutineScope sebagai dependensi dalam konstruktornya. Saat
ViewModelStoreOwner menghapus ViewModel di akhir siklus prosesnya, ViewModel juga akan membatalkan CoroutineScope.
class MyViewModel(
private val coroutineScope: CoroutineScope =
CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
) : ViewModel() {
// Other ViewModel logic ...
override fun onCleared() {
coroutineScope.cancel()
}
}
Dari lifecycle versi 2.5 dan yang lebih baru,
Anda dapat meneruskan satu atau beberapa objek Closeable
ke konstruktor ViewModel yang otomatis ditutup saat
instance ViewModel dihapus.
class CloseableCoroutineScope(
context: CoroutineContext = SupervisorJob() + Dispatchers.Main.immediate
) : Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}
class MyViewModel(
private val coroutineScope: CoroutineScope = CloseableCoroutineScope()
) : ViewModel(coroutineScope) {
// Other ViewModel logic ...
}
Praktik terbaik
Berikut adalah beberapa praktik terbaik utama yang sebaiknya Anda ikuti saat mengimplementasikan ViewModel:
- Karena cakupan, gunakan ViewModel sebagai detail implementasi pemegang status tingkat layar. Jangan menggunakannya sebagai pemegang status komponen UI yang dapat digunakan kembali seperti grup chip atau formulir. Jika tidak, Anda akan mendapatkan instance ViewModel yang sama dalam penggunaan komponen UI yang sama dengan cara berbeda dalam ViewModelStoreOwner yang sama, kecuali jika Anda menggunakan kunci model tampilan eksplisit per chip.
- ViewModel tidak boleh mengetahui detail implementasi UI. Pastikan nama metode yang ditampilkan oleh ViewModel API dan kolom status UI seumum mungkin. Dengan cara ini, ViewModel Anda dapat mengakomodasi jenis UI apa pun: ponsel, perangkat foldable, tablet, atau bahkan Chromebook.
- Karena berpotensi dapat aktif lebih lama dari
ViewModelStoreOwner, ViewModel tidak boleh menyimpan referensi apa pun yang terkait dengan API terkait siklus proses sepertiContextatauResourcesuntuk mencegah kebocoran memori. - Jangan meneruskan ViewModel ke class, fungsi, atau komponen UI lainnya. Karena platform mengelolanya, Anda harus menyimpannya sedekat mungkin dengan Anda—dekat dengan Aktivitas, fungsi composable tingkat layar, atau tujuan Navigasi. Hal ini mencegah komponen dengan tingkat lebih rendah mengakses lebih banyak data dan logika daripada yang dibutuhkan.
Informasi lebih lanjut
Ketika data Anda bertambah menjadi lebih kompleks, Anda mungkin memilih untuk memiliki class terpisah yang tugasnya hanya
untuk memuat data. Tujuan dari ViewModel adalah untuk mengenkapsulasi data bagi
pengontrol UI agar data dapat bertahan saat terjadi perubahan konfigurasi. Untuk informasi
tentang cara memuat, mempertahankan, dan mengelola data di seluruh perubahan konfigurasi, lihat
Status UI Tersimpan.
Panduan Arsitektur Aplikasi Android menyarankan pembuatan class repositori untuk penanganan fungsi-fungsi ini.
Referensi lainnya
Untuk informasi lebih lanjut tentang class ViewModel, lihat referensi
berikut.
Dokumentasi
Melihat konten
Contoh
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Menggunakan coroutine Kotlin dengan komponen yang mendukung siklus proses
- Menyimpan status UI
- Memuat dan menampilkan data yang dibagi-bagi