Ringkasan ViewModel Bagian dari Android Jetpack.
Class ViewModel
dirancang
untuk menyimpan dan mengelola data terkait UI dengan cara yang berbasis siklus proses. Class ViewModel
memungkinkan
data bertahan saat terjadi perubahan konfigurasi seperti pada saat rotasi layar.
Framework Android mengelola siklus proses pengontrol UI, seperti aktivitas dan fragmen. Framework ini dapat memutuskan untuk memusnahkan atau membuat ulang pengontrol UI sebagai respons terhadap tindakan tertentu dari pengguna atau peristiwa perangkat yang benar-benar di luar kendali Anda.
Jika sistem memusnahkan atau membuat ulang pengontrol UI, setiap data terkait UI sementara yang Anda simpan di dalam pengontrol UI akan hilang. Misalnya, aplikasi Anda mungkin menyertakan
daftar pengguna dalam salah satu aktivitasnya. Saat aktivitas dibuat ulang untuk
perubahan konfigurasi, aktivitas baru tersebut harus menarik ulang daftar pengguna. Untuk
data sederhana, aktivitas dapat menggunakan
metode
onSaveInstanceState()
dan memulihkan datanya dari paket di onCreate()
, tetapi pendekatan ini hanya cocok untuk data dalam jumlah sedikit yang dapat diserialisasi kemudian dideserialisasi, bukan untuk data yang berpotensi memiliki jumlah besar, seperti daftar pengguna atau bitmap.
Masalah lainnya yaitu pengontrol UI seringkali harus melakukan panggilan asinkron yang membutuhkan beberapa saat untuk ditampilkan. Pengontrol UI harus mengelola panggilan ini dan memastikan sistem akan membersihkan panggilan setelah panggilan dimusnahkan untuk menghindari kemungkinan kebocoran memori. Pengelolaan ini memerlukan banyak pemeliharaan, dan dalam kasus di mana objek dibuat ulang untuk perubahan konfigurasi, pembuatan ulang objek menjadi pemborosan resource karena objek mungkin harus melakukan panggilan ulang yang sebelumnya sudah dilakukan.
Pengontrol UI seperti aktivitas dan fragmen terutama ditujukan untuk menampilkan data UI, bereaksi pada tindakan pengguna, atau menangani komunikasi sistem operasi, misalnya permintaan izin. Mewajibkan pengontrol UI untuk juga bertanggung jawab atas pemuatan data dari database atau jaringan, akan menambahkan penggelembungan pada kelas. Menetapkan tanggung jawab yang berlebih pada pengontrol UI dapat mengakibatkan satu kelas yang mencoba menangani semua tugas aplikasi dengan sendirinya, dan bukan mendelegasikan tugas-tugas tersebut ke kelas lainnya. Menetapkan tanggung jawab yang berlebih pada pengontrol UI dengan cara seperti ini juga membuat pengujian menjadi jauh lebih sulit.
Akan lebih mudah dan lebih efisien untuk memisahkan tampilan kepemilikan data dari logika pengontrol UI.
Mengimplementasikan ViewModel
Komponen Arsitektur memberikan class penunjang ViewModel
bagi pengontrol
UI yang bertanggung jawab
untuk menyediakan data bagi UI.
Objek ViewModel
otomatis disimpan pada saat perubahan konfigurasi sehingga data yang disimpan segera tersedia
untuk instance aktivitas atau fragmen berikutnya. Misalnya,
jika Anda perlu menampilkan daftar pengguna di aplikasi, pastikan untuk memberikan
tanggung jawab perolehan dan penyimpanan daftar pengguna
ke ViewModel
, bukan
pada aktivitas atau fragmen, seperti yang ditunjukkan oleh kode contoh berikut:
Kotlin
class MyViewModel : ViewModel() { private val users: MutableLiveData<List<User>> by lazy { MutableLiveData().also { loadUsers() } } fun getUsers(): LiveData<List<User>> { return users } private fun loadUsers() { // Do an asynchronous operation to fetch users. } }
Java
public class MyViewModel extends ViewModel { private MutableLiveData<List<User>> users; public LiveData<List<User>> getUsers() { if (users == null) { users = new MutableLiveData<List<User>>(); loadUsers(); } return users; } private void loadUsers() { // Do an asynchronous operation to fetch users. } }
Anda kemudian dapat mengakses daftar tersebut dari aktivitas dengan cara sebagai berikut:
Kotlin
class MyActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // Create a ViewModel the first time the system calls an activity's onCreate() method. // Re-created activities receive the same MyViewModel instance created by the first activity. // Use the 'by viewModels()' Kotlin property delegate // from the activity-ktx artifact val model: MyViewModel by viewModels() model.getUsers().observe(this, Observer<List<User>>{ users -> // update UI }) } }
Java
public class MyActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { // Create a ViewModel the first time the system calls an activity's onCreate() method. // Re-created activities receive the same MyViewModel instance created by the first activity. MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class); model.getUsers().observe(this, users -> { // update UI }); } }
Jika aktivitas dibuat ulang, aktivitas akan menerima instance MyViewModel
yang
sama seperti yang dibuat oleh aktivitas pertama. Saat aktivitas pemilik selesai, framework memanggil metode
onCleared()
milik
objek ViewModel
agar metode tersebut dapat merapikan resource.
Objek ViewModel
dirancang
untuk aktif lebih lama dibandingkan proses instantiasi tampilan tertentu
atau LifecycleOwners
. Rancangan ini
juga berarti bahwa Anda dapat menulis pengujian yang
mencakup ViewModel
dengan lebih mudah
karena rancangan tidak mengetahui tampilan dan
objek Lifecycle
.
Objek ViewModel
dapat berisi
LifecycleObservers
,
seperti
objek LiveData
. Namun,
objek ViewModel
tidak boleh
mengamati perubahan pada observable berbasis siklus proses,
seperti objek LiveData
.
Jika
ViewModel
membutuhkan
konteks Application
, misalnya untuk menemukan layanan sistem,
ViewModel dapat memperluas
class AndroidViewModel
dan
memiliki konstruktor yang menerima Application
di
dalam konstruktor, karena class Application
menjangkau Context
.
Siklus proses ViewModel
Objek ViewModel
dicakupkan
ke
Lifecycle
yang diteruskan
ke ViewModelProvider
saat menerima
ViewModel
. ViewModel
tetap
berada di memori
sampai Lifecycle
yang
dicakupnya hilang secara permanen: dalam kasus aktivitas, yaitu saat
aktivitas selesai, sementara dalam kasus fragmen, yaitu sampai fragmen terlepas.
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. Status dasar yang sama juga diterapkan untuk siklus proses suatu fragmen.
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 dimusnahkan.
Berbagi data antar-fragmen
Sangatlah umum bagi dua fragmen atau lebih dalam suatu aktivitas untuk perlu saling berkomunikasi satu sama lain. Bayangkan kasus umum fragmen tampilan terpisah (master-detail
),
yakni saat Anda memiliki fragmen yang memungkinkan pengguna memilih item dari
daftar dan fragmen lain yang menampilkan isi item yang dipilih. Kasus seperti ini
tidaklah sepele karena kedua fragmen harus mendefinisikan beberapa deskripsi antarmuka, dan
aktivitas pemilik harus mengikat keduanya secara bersamaan. Selain itu,
kedua fragmen harus menangani skenario saat fragmen lain belum
dibuat atau terlihat.
Titik permasalahan umum ini dapat diatasi menggunakan
objek ViewModel
. Fragmen
ini dapat
berbagi ViewModel
menggunakan cakupan
aktivitas untuk menangani komunikasi ini, seperti yang ditunjukkan dalam kode contoh
berikut:
Kotlin
class SharedViewModel : ViewModel() { val selected = MutableLiveData<Item>() fun select(item: Item) { selected.value = item } } class MasterFragment : Fragment() { private lateinit var itemSelector: Selector // Use the 'by activityViewModels()' Kotlin property delegate // from the fragment-ktx artifact private val model: SharedViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) itemSelector.setOnClickListener { item -> // Update the UI } } } class DetailFragment : Fragment() { // Use the 'by activityViewModels()' Kotlin property delegate // from the fragment-ktx artifact private val model: SharedViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) model.selected.observe(viewLifecycleOwner, Observer<Item> { item -> // Update the UI }) } }
Java
public class SharedViewModel extends ViewModel { private final MutableLiveData<Item> selected = new MutableLiveData<Item>(); public void select(Item item) { selected.setValue(item); } public LiveData<Item> getSelected() { return selected; } } public class MasterFragment extends Fragment { private SharedViewModel model; public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); itemSelector.setOnClickListener(item -> { model.select(item); }); } } public class DetailFragment extends Fragment { public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class); model.getSelected().observe(getViewLifecycleOwner(), item -> { // Update the UI. }); } }
Perhatikan bahwa kedua fragmen mengambil aktivitas yang memuatnya. Dengan begitu,
saat setiap fragmen menerima
ViewModelProvider
,
fragmen tersebut menerima instance SharedViewModel
yang sama,
yang dicakupkan ke aktivitas ini.
Pendekatan ini memberikan manfaat seperti berikut:
- Aktivitas tidak perlu melakukan, atau mengetahui apa pun tentang komunikasi ini.
- Fragmen tidak perlu mengenali satu sama lainnya
selain kontrak
SharedViewModel
. Jika salah satu fragmen hilang, fragmen lainnya akan terus bekerja seperti biasa. - Setiap fragmen memiliki siklus prosesnya sendiri, dan tidak terpengaruh oleh siklus proses fragmen lain. Jika satu fragmen menggantikan yang lainnya, UI terus bekerja tanpa masalah.
Mengganti Loader dengan ViewModel
Class Loader seperti CursorLoader
sering digunakan untuk
menyimpan data di UI aplikasi yang disinkronkan dengan database. Anda dapat menggunakan
ViewModel
, dengan
beberapa class lainnya, untuk menggantikan loader. Penggunaan
ViewModel
memisahkan
pengontrol UI dari operasi pemuatan data, yang berarti Anda memiliki lebih sedikit referensi
yang kuat antar-class.
Pada satu pendekatan umum dalam penggunaan loader,
suatu aplikasi mungkin menggunakan CursorLoader
untuk
mengamati konten suatu database. Saat suatu nilai dalam database berubah,
loader secara otomatis memicu pemuatan ulang data dan mengupdate UI:

ViewModel
berfungsi
dengan Room dan
LiveData sebagai pengganti loader.
ViewModel
memastikan bahwa
data bertahan saat terjadi perubahan konfigurasi ponsel.
Room memberikan informasi
ke LiveData
saat database
berubah, kemudian
LiveData mengupdate UI dengan data baru.

Menggunakan coroutine dengan ViewModel
ViewModel
mencakup dukungan untuk coroutine Kotlin. Untuk informasi selengkapnya, lihat
Menggunakan coroutine Kotlin dengan Komponen Arsitektur Android.
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
Menyimpan Status UI.
Panduan Arsitektur Aplikasi Android menyarankan pembuatan class repositori untuk penanganan fungsi-fungsi ini.
Referensi lainnya
Untuk informasi selengkapnya
tentang class ViewModel
, lihat referensi berikut.
Contoh
- Sampel dasar Komponen Arsitektur Android
- Sunflower, yakni aplikasi berkebun yang mengilustrasikan praktik terbaik pengembangan Android dengan Android Jetpack.
Codelab
- Android Room dengan View (Java) (Kotlin)
- Codelab komponen berbasis siklus proses Android
Blog
- ViewModel: Contoh Sederhana
- ViewModels: Persistensi, onSaveInstanceState(), Memulihkan Status dan Loader UI
- ViewModel dan LiveData: Pola + Anti-Pola
- Menjelaskan Kotlin: Memahami Sintaksis Lambda Singkat
- Menjelaskan Kotlin: Fungsi cakupan
- Menjelaskan Kotlin: Kapan menggunakan pengakses kustom
- Pemuatan Data Berbasis Siklus Proses dengan Komponen Arsitektur