Belajar View Model dan Lifecycle didalam Architecture Component


View Model dan Lifecycle

Pada modul kali ini Anda akan mempelajari tentang ViewModel dan Lifecycle sebagai bagian dari Android Architecture Component.



ViewModel

Di modul pengenalan Android Jetpack, kita sempat membahas sekilas tentang ViewModel. Pada modul ini, Anda akan mempelajari lebih dalam tentang ViewModel hingga cara mengimplementasikan ke dalam proyek Android.

Sebelum masuk ke materi ViewModel, Anda perlu mengetahui bagaimana cara Framework Android mengelola lifecycle dari UI controller seperti Activity atau Fragment. UI controller berfungsi untuk menampilkan data ke UI, memberi aksi terhadap tindakan pengguna atau menangani komunikasi sistem informasi seperti permintaan permission atau perizinan. 

Selain itu, UI controller juga memiliki kemampuan untuk mempertahankan data. Seperti di modul sebelumnya, ketika Anda mendapatkan sebuah data dari aksi tertentu seperti data volume, maka untuk mempertahankannya Anda perlu melakukan sesuatu. 

Apa itu? Anda perlu menyimpan data tersebut dengan memanggil onSaveInstancestate() dan menampilkan data tersebut di onCreate dengan bantuan Bundle.

Hal di atas bisa dilakukan karena data yang Anda pertahankan berukuran kecil. Namun bagaimana jika data yang Anda jaga berjumlah besar seperti daftar user atau Bitmap? Tentu manajemen UI controller akan bermasalah.

Masalah lain yang terjadi adalah UI controller kerap memanggil secara asynchronous dan membutuhkan waktu tertentu untuk mendapatkan hasil dari proses tersebut. 

UI controller perlu mengatur setiap pemanggilan dan memastikan tiada potensi kebocoran memori. Jika beban yang diberikan ke UI controller terlalu berlebihan, tingkat kesulitan dalam melakukan pengujian akan meningkat. 

Akan lebih mudah dan lebih efisien jika Anda memisahkan sumber data dengan logika UI controller.

Implementasi ViewModel

Architecture Components menyediakan kelas ViewModel untuk membantu UI controller menyiapkan data yang akan ditampilkan ke UI. Obyek ViewModel akan selalu dipertahankan selama ada configuration changes

Alhasil, data yang dimilikinya akan segera tersedia untuk Activity atau Fragment selanjutnya. Contohnya jika Anda perlu menampilkan data pengguna di aplikasi Anda, pastikan bahwa Anda sudah menyimpan data pengguna ke kelas ViewModel. Berikut ini adalah contoh ilustrasinya:

Kotlin

class MyViewModel : ViewModel() {
var users: MutableLiveData<List<User>>? = null
get() {
if (field == null) {
field = MutableLiveData<List<User>>()
loadUsers()
}
return field
}
private set

private fun loadUsers() {
// Melakukan proses asynchronous untuk mendapatkan data pengguna.
}
}
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() {
// Melakukan proses asynchronous untuk mendapatkan data pengguna.
}
}

Kemudian Anda dapat mengakses daftar pengguna dari Activity seperti berikut:

Kotlin

class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Membuat ViewModel saat Activity berada di metode onCreate().
val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
model.users?.observe(this, users -> {
// Ketika ada data users, maka UI secara otomatis terupdate.
})
}
}

Java

public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// Membuat ViewModel saat Activity berada di metode onCreate().
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// Ketika ada data users, maka UI secara otomatis terupdate.
});
}
}

Catatan:
Pada kode di atas, pasti Anda masih belum familiar dengan beberapa komponen seperti LiveData. Untuk materi LiveData kita akan membahasnya di modul 2. Saat ini kita akan fokus dengan penggunaan ViewModel.

Pada kode di atas ketika Activity dimuat ulang, maka Activity tersebut akan melakukan instance ViewModel yang sama ketika Activity dibentuk pertama kali. Ketika Activity berada dalam proses selesai, maka framework UI akan memanggil metode onCleared di mana obyek ViewModel dapat dibersihkan.

Lifecycle dari ViewModel

Jika digambarkan dengan skema maka akan menjadi seperti ini:

Dq95KakvNrkKCQy4v-s1oMVhP8z0f4q1o96jlOtvZq9iyvZNnKoImtRvmXOm4_5g-zCyGWr-xQAKy70bJ5DZtRt4uQK8wP2hPUWEP2NKVvlaOo38xQE1G2ksFewptBwlZ2OOHKW-

Gambar di atas mengilustrasikan berbagai keadaan lifecycle dari Activity saat ia mengalami rotasi dan kemudian selesai. Gambar di atas juga menunjukkan keterikatan ViewModel terhadap Activity hingga Activity selesai dan dihancurkan.

Perbandingan ViewModel dengan savedInstanceState

PembedaViewModelsavedInstanCestate
Lokasi penyimpanan
Di memory
Serialized ke dalam disk
Mampu bertahan dari configuration change
Ya
Ya
Bertahan dari proses mematikan app yang dimulai dari sistem
Tidak
Ya
Bertahan dari kesalahan aktifitas user atau onFinish()
Tidak
Tidak
Keterbatasan Data
Obyek kompleks akan baik baik saja, namun ruangnya dibatasi oleh memori yang tersedia
Hanya untuk tipe primitif dan obyek kecil dan sederhana seperti String, Integer dll.
Waktu Read/Write
Cepat (Hanya mengakses memori)
Lambat (Membutuhkan serialisasi / deserialisasi dan akses ke disk)

Jika dilihat pada tabel di atas, penggunaan ViewModel lebih baik dibanding SaveInstantState, baik waktu baca dan tulisnya maupun dalam obyek yang disimpan. Makin keren kan?

Untuk lebih jelasnya, yuk cek tautan berikut:

Lifecycle

Pada modul sebelumnya, Anda sudah mengetahui apa itu Lifecycle. Jadi seperti apa penggunaan Lifecycle dalam sebuah Activity? Kita ambil contoh dari kasus saat sebuah Activity mengambil lokasi.

Ini adalah kelas MyLocationListener:

Kotlin

internal class MyLocationListener(context: Context?, callback: Callback?) {
fun start() { // menghubungkan ke sistem location service
}

fun stop() { // memutuskan sistem location service
}
}

Java

class MyLocationListener {
public MyLocationListener(Context context, Callback callback) {
// ...
}


void start() {
// menghubungkan ke sistem location service
}


void stop() {
// memutuskan sistem location service
}
}

Dan di bawah ini adalah kelas Activity yang mengmiplementasikan MyLocationListener.

Kotlin

internal class MyActivity : AppCompatActivity() {
private var myLocationListener: MyLocationListener? = null

override fun onCreate(savedInstanceState: Bundle?) {
myLocationListener = MyLocationListener(this, location){

}
}
public override fun onStart() {
super.onStart()
myLocationListener?.start()
}

public override fun onStop() {
super.onStop()
myLocationListener?.stop()
}
}

Java

class MyActivity extends AppCompatActivity {
private MyLocationListener myLocationListener;


@Override
public void onCreate(...) {
myLocationListener = new MyLocationListener(this, (location) -> {
// memperbarui UI
});
}
@Override
public void onStart() {
super.onStart();
myLocationListener.start();
// mengatur komponen lain jika dibutuhkan untuk merespon
// lifecycle activity
}


@Override
public void onStop() {
super.onStop();
myLocationListener.stop();
// mengatur komponen lain jika dibutuhkan untuk merespon
// lifecycle activity
}
}

Jika Anda perhatikan kode di atas, normal-normal saja ya kelihatannya? Pun saat dijalankan, tak akan terjadi bug atau masalah di dalamnya. Kelas MyLocationService berfungsi untuk mengelola ketika terkoneksi atau tidak.

Namun, jika diperhatikan sekali lagi, ketika mengimplementasikan kelas MyLocationService, terlalu banyak panggilan yang hanya untuk mengelola UI atau komponen lain sebagai reaksi dari keadaan Lifecycle. 

Mengelola banyak komponen di dalam metode Lifecycle seperti onStart() dan onStop(), akan membuat Anda kesulitan saat maintenance. Komponen android.arch.lifecycle menyediakan kelas dan interface yang membantu Anda mengatasi masalah ini dengan cara mudah dan terisolasi.

Seperti yang sudah dipaparkan di atas, Lifecycle memilih fungsi untuk menyimpan informasi mengenai state dari komponen Lifecycle seperti Activity atau Fragment dan memungkinkan sebuah obyek untuk melakukan observasi perubahan keadaan dari sebuah Lifecycle. 

Lifecycle mempunyai dua komponen utama untuk melacak perubahan keadaan lifecycle yaitu state dan event.
  1. Event atau Peristiwa : Peristiwa dari Lifecycle yang dikirimkan dari sebuah Framework dan kelas Lifecycle. Event Lifecycle akan memetakan event callback atau balikan event dalam Activity atau Fragment.
  2. State atau keadaan : Sebuah keadaan dari komponen yang dilacak dari obyek Lifecycle.
Jika dijabarkan dalam bentuk grafik maka menjadi seperti ini:

ptIQSvOV31xdV4wU304zEZsN3WzMWa9LujvJfmU5YmEN6y3NTAYOADpQzBoUQJGBgnTYzXrNKKaIW2aZBY_A-YjwuCHuXRtAvsCnyp9sJmhiDSJmQh88iWVusAA8AYPpF3fXC6-0

Kita asumsikan bahwa sebuah keadaan atau state dari lifecycle adalah simpul dari grafik dan peristiwa atau event adalah tepi antara simpul-simpul tersebut.

Suatu kelas dapat memonitor keadaan sebuah siklus dari komponen Lifecycle dengan menambahkan annotations ke metodenya. 

Kemudian Anda bisa menambahkan sebuah observer atau pengamat dengan memanggil metode addObserver() dari kelas Lifecycle dan mengelola hasil dari observer tersebut, seperti yang ditunjukkan dalam contoh berikut:

Kotlin

class MyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectListener() {
...
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun disconnectListener() {
...
}
}

Java

public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void connectListener() {
...
}


@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void disconnectListener() {
...
}
}

Dan cara mengimplementasikan di Activity seperti ini:

Kotlin

myLifecycleOwner.getLifecycle.addObserver(MyObserver())

Java

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

Pada contoh di atas, objek myLifecycleOwner mengimplementasikan interface LifecycleOwner. MyObserver()-pun dipanggil di kelas utama Anda.

Anda bisa melihat deskripsi lebih lengkapnya di sini:
https://developer.android.com/topic/libraries/architecture/lifecycle

Komentar