Belajar ViewModel Dengan Contoh Project Aplikasi Android
Tujuan
Pada codelab kali ini, Anda akan mempelajari bagaimana mengimplementasikan ViewModel dalam membuat aplikasi Android. Hasil dari codelab kali ini akan menjadi seperti ini:
Logika Dasar
Melakukan input → mengirim data ke ViewModel → melakukan penghitungan → mengirim data ke Activity → melakukan perubahan rotasi → data masih terjaga.
Codelab ViewModel
- Buat proyek baru di Android Studio dengan kriteria sebagai berikut:
Nama Project MyViewModel Target & Minimum Target SDK Phone and Tablet, Api level 21 Tipe Activity Empty Activity Activity Name MainActivity Use AndroidX artifacts True Language Kotlin/Java - Selanjutnya tambahkan library ViewModel di build.gradle(module:App):
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
- Buka layout activity_main.xml, kemudian ubah kode di dalamnya menjadi seperti ini:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/length" />
<EditText
android:id="@+id/edt_length"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:inputType="numberDecimal"
android:lines="1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/width" />
<EditText
android:id="@+id/edt_width"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:inputType="numberDecimal"
android:lines="1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/height" />
<EditText
android:id="@+id/edt_height"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:inputType="numberDecimal"
android:lines="1" />
<Button
android:id="@+id/btn_calculate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/calculate" />
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/result"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
Tambahkan juga resource string-nya. Tambahkan semua string yang akan digunakan di project ini. Buka berkas strings.xml dan tambahkan kode berikut ini:
<resources>
<string name="app_name">MyViewModel</string>
<string name="width">Lebar</string>
<string name="result">Hasil</string>
<string name="calculate">Hitung</string>
<string name="height">Tinggi</string>
<string name="length">Panjang</string>
</resources>
Kotlin |
class MainViewModel : ViewModel() { |
Java |
public class MainViewModel extends ViewModel { |
Setelah Anda membuat kelas MainViewModel, selanjutnya Anda perlu mengubah dan menambahkan kode pada kelas MainActivity menjadi seperti berikut:
Untuk mendapatkan result, cukup dengan:
Kotlin class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
displayResult()
btn_calculate.setOnClickListener {
val width = edt_width.text.toString()
val height = edt_height.text.toString()
val length = edt_length.text.toString()
when {
width.isEmpty() -> {
edt_width.error = "Masih kosong"
}
height.isEmpty() -> {
edt_height.error = "Masih kosong"
}
length.isEmpty() -> {
edt_length.error = "Masih kosong"
}
else -> {
viewModel.calculate(width, height, length)
displayResult()
}
}
}
}
private fun displayResult() {
tv_result.text = viewModel.result.toString()
}
}
Javapublic class MainActivity extends AppCompatActivity {
private EditText edtWidth, edtHeight, edtLength;
private TextView tvResult;
private MainViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edtWidth = findViewById(R.id.edt_width);
edtHeight = findViewById(R.id.edt_height);
edtLength = findViewById(R.id.edt_length);
tvResult = findViewById(R.id.tv_result);
viewModel = new ViewModelProvider(this).get(MainViewModel.class);
displayResult();
findViewById(R.id.btn_calculate).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String width = edtWidth.getText().toString();
String height = edtHeight.getText().toString();
String length = edtLength.getText().toString();
if (width.isEmpty()) {
edtWidth.setError("Masih kosong");
} else if (height.isEmpty()) {
edtHeight.setError("Masih kosong");
} else if (length.isEmpty()) {
edtLength.setError("Masih kosong");
} else {
viewModel.calculate(width, height, length);
displayResult();
}
}
});
}
private void displayResult() {
tvResult.setText(String.valueOf(viewModel.result));
}
}- Jalankan aplikasi yang sudah Anda buat dan lakukan perubahan rotasi dari landscape ke portrait atau sebaliknya, maka aplikasi akan mempertahankan data pada kelas MainViewModel.
Dengan memanfaatkan ViewModel, Anda bisa mempertahankan data sesuai kebutuhan Anda.
Bedah Kode
Library ViewModel
Saat Anda akan menggunakan komponen ViewModel, Anda perlu menambahkan satu library berikut untuk memenuhi kebutuhan tersebut.
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc02'
Library di atas juga sudah termasuk LiveData dan Lifecycle.
MainViewModel
Anda bisa melihat kode pada kelas MainViewModel di bawah ini:
Kotlin |
class MainViewModel : ViewModel() { |
Java |
class MainViewModel extends ViewModel { |
Dengan menambahkan turunan kelas ViewModel ke kelas MainViewModel, itu menandakan bahwa kelas tersebut menjadi kelas ViewModel.
Segala sesuatu yang ada di kelas tersebut akan terjaga selama Activity masih dalam keadaan aktif. Pada kelas MainViewModel, nilai dari result akan selalu dipertahankan selama MainViewModel masih terikat dengan Activity.
ViewModelProvider
Lalu bagaimana cara menyambungkan kelas MainViewModel dengan MainActivity? Anda bisa lihat kode di bawah ini:
Kotlin |
viewModel = ViewModelProvider(this)[MainViewModel::class.java] |
Java |
viewModel = new ViewModelProvider(this).get(MainViewModel.class); |
Ketika Activity membutuhkan ViewModel, Anda cukup memanggil kelas ViewModelProvider dengan parameter context. Karena inisialisasi dilakukan di Activity, maka kita menggunakan this sebagai context.
Kemudian input .get() diisi dengan kelas ViewModel mana yang akan dihubungkan dengan Activity.
Mendapatkan Value dari ViewModel
Jika pada kelas ViewModel, sudah ada metode calculate yang berfungsi untuk melakukan perkalian dari input lebar, panjang dan tinggi. Maka Anda cukup memanggil metode tersebut seperti ini:
Kotlin |
viewModel.calculate(width, height, length) |
Java |
viewModel.calculate(width, height, length); |
Untuk mendapatkan result, cukup dengan:
Kotlin |
viewModel.result |
Java |
viewModel.result |
Namun jika Anda perhatikan, setiap perubahan dari result tidak bisa secara otomatis terganti. Anda perlu memanggil metode displayResult() untuk memperbarui nilai result.
Hal ini karena Anda belum menggunakan LiveData yang bisa otomatis memperbarui teks ketika ada perubahan data. Tenang saja, Anda akan mempelajari tentang ini di latihan selanjutnya.
Anda bisa unduh proyek di atas pada tautan berikut:
Source Code Latihan MyViewModel
Source Code Latihan MyViewModel
ViewModel merupakan bagian kecil dari Architecture Component. Akan ada beberapa komponen lain, seperti LiveData dan Room. Komponen lain tersebut akan Anda pelajari pada materi selanjutnya.