news

Senin, 15 Juni 2020

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:

2019052911551920a0e74297aa510bd91cc2f6eccadcae.gif

Logika Dasar

Melakukan input → mengirim data ke ViewModel → melakukan penghitungan → mengirim data ke Activity → melakukan perubahan rotasi → data masih terjaga.


Codelab ViewModel

  1. Buat proyek baru di Android Studio dengan kriteria sebagai berikut:
    Nama ProjectMyViewModel
    Target & Minimum Target SDKPhone and Tablet, Api level 21
    Tipe ActivityEmpty Activity
    Activity NameMainActivity
    Use AndroidX artifacts True
    LanguageKotlin/Java
  2. Selanjutnya tambahkan library ViewModel di build.gradle(module:App):
    implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'

  3. 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>

Selanjutnya, buat kelas baru dengan nama MainViewModel. Ubah dan tambahkan kode pada kelas tersebut menjadi seperti ini:

Kotlin

class MainViewModel : ViewModel() {
var result = 0

fun calculate(width: String, height: String, length: String) {
result = width.toInt() * height.toInt() * length.toInt()
}
}

Java

public class MainViewModel extends ViewModel {

int result = 0;

void calculate(String width, String height, String length) {
result = Integer.parseInt(width) * Integer.parseInt(height) * Integer.parseInt(length);
}
}
Setelah Anda membuat kelas MainViewModel, selanjutnya Anda perlu mengubah dan menambahkan kode pada kelas MainActivity menjadi seperti berikut:
  1. 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()
    }

    }

    Java

    public 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));
    }

    }
  2. Jalankan aplikasi yang sudah Anda buat dan lakukan perubahan rotasi dari landscape ke portrait atau sebaliknya, maka aplikasi akan mempertahankan data pada kelas MainViewModel.
    Qwzrcm0ZAkrUy8Ox5yMxOSvr-TI2TygzJOSvtS00zLUfnwjQ9OTHll9jdeK0nr5O7LZzjG2QM7qymuwc0vuJKnD2d6pL_z8cS6_0sQSzQqsfijhX4JGTO36htY0ApepZ1MA8_12b
    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() {
var result = 0

fun calculate(width: String, height: String, length: String) {
result = width.toInt() * height.toInt() * length.toInt()
}
}

Java

class MainViewModel extends ViewModel {
int result = 0;

void calculate(String width, String height, String length){
result = Integer.parseInt(width) * Integer.parseInt(height) * Integer.parseInt(length);
}
}
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

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.