Selasa, 04 Juni 2024

ViewModel and State in Compose - Unscramble

Nama : Naily Khairiya

NRP : 5025201244

Kelas : PPB - I


Aplikasi Unscramble adalah game pengacak ejaan kata untuk satu pemain. Aplikasi menampilkan kata acak, dan pemain harus menebak kata tersebut menggunakan semua huruf yang ditampilkan. Pemain akan mendapatkan poin jika kata tersebut benar. Jika tidak, pemain dapat mencoba menebak kata sebanyak-banyaknya. Aplikasi ini juga memiliki opsi untuk melewati kata saat ini. Di pojok kanan atas, aplikasi menampilkan jumlah kata, yaitu jumlah kata acak yang dimainkan dalam game saat ini. Ada 10 kata acak per game. 


Untuk mendapatkan kode awal

$ git clone
https://github.com/google-developer-training/basic-android-kotlin-compose-training-unscramble.git
$ cd basic-android-kotlin-compose-training-unscramble
$ git checkout starter


Aplikasi ini adalah game tebak kata sederhana. Pengguna diminta untuk menebak kata yang diacak. Kata acak saat ini di-hardcode menjadi "scrambleun". Pengguna memasukkan tebakan mereka di kolom teks. Skor dan jumlah kata ditampilkan di bagian bawah layar. Namun, terdapat beberapa bug dalam aplikasi awal:

  • Kata acak di-hardcode, bukan dipilih secara acak dari daftar kata.
  • Kolom teks tebakan tidak diperbarui saat pengguna memasukkan tebakan.
  • Peristiwa klik tombol "Submit" dan "Skip" belum diterapkan.
  • Dialog skor akhir belum ditampilkan di akhir game.


Berikut langkah penyelesaiannya.

1️⃣ Pelajari tentang arsitektur aplikasi

Arsitektur aplikasi membantu Anda mengatur aplikasi dengan membagi tanggung jawab ke dalam class yang berbeda. Hal ini  membuat aplikasi lebih mudah diubah dan ditambahkan fitur baru, serta memudahkan kolaborasi tim. Prinsip Utama:

  • Pemisahan fokus: Bagi aplikasi menjadi beberapa class dengan tanggung jawab yang terpisah.
  • UI dari model: Model (data) terpisah dari UI (tampilan).

Arsitektur yang Direkomendasikan:

Setidaknya memiliki 2 lapisan yaitu : 

  • Lapisan UI: Menampilkan data di layar. Terdiri dari elemen UI dan pemegang status (seperti ViewModel).
  • Lapisan data: Menyimpan, mengambil, dan menampilkan data.

ViewModel:

  • Menyimpan dan menampilkan status UI.
  • Memisahkan UI dari model.
  • Mempertahankan data saat perubahan konfigurasi.

Status UI:

  • Data aplikasi yang ditampilkan di UI.
  • Diperbarui secara otomatis saat data aplikasi berubah.

Ketetapan:

  • Status UI tidak dapat diubah secara langsung di UI.
  • Mencegah inkonsistensi data dan bug.


2️⃣ Menambahkan ViewModel

Kita perlu menyimpan data game di ViewModel.

  • Tambahkan dependency : 

implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1"


  • Di paket ui, buat class/file Kotlin bernama GameViewModel. Perluas dari class ViewModel.
  • Dalam paket ui, tambahkan class model untuk UI status yang disebut GameUiState. Jadikan class data dan tambahkan variabel untuk kata acak saat ini.

StateFlow

  • Di class GameViewModel, tambahkan properti _uiState 
    import kotlinx.coroutines.flow.MutableStateFlow

    // Game UI state
    private val _uiState = MutableStateFlow(GameUiState())
  • Di file GameViewModel.kt, tambahkan properti pendukung ke uiState yang bernama _uiState. Beri nama properti uiState dan berjenis StateFlow<GameUiState>
Menampilkan kata acak tanpa pola

  • Di GameViewModel, tambahkan properti bernama currentWord dari jenis String untuk menyimpan kata acak saat ini.
  • Tambahkan metode bantuan untuk pilih kata acak dari daftar dan acaklah. Beri nama pickRandomWordAndShuffle() tanpa parameter input, lalu buat fungsi tersebut menampilkan String.
  • Di GameViewModel, tambahkan properti berikut setelah properti currentWord agar berfungsi sebagai kumpulan yang dapat diubah untuk menyimpan kata yang telah digunakan.
  • Tambahkan metode helper lain untuk mengacak kata saat ini yang disebut shuffleCurrentWord() yang menggunakan String dan menampilkan String yang diacak.
  • Tambahkan fungsi bantuan untuk melakukan inisialisasi game yang disebut resetGame(). Gunakan fungsi ini nanti untuk memulai dan memulai ulang game. Pada fungsi ini, hapus semua kata dalam kumpulan usedWords, lakukan inisialisasi _uiState. Pilih kata baru untuk currentScrambledWord menggunakan pickRandomWordAndShuffle().
  • Tambahkan blok init ke GameViewModel dan panggil resetGame() dari blok tersebut.
  • Ketika membangun aplikasi sekarang, Kita masih belum melihat perubahan pada UI. Kita tidak meneruskan data dari ViewModel ke composable di GameScreen.
3️⃣  Merancang Compose UI 

  • Pada fungsi GameScreen, teruskan argumen kedua dari jenis GameViewModel dengan nilai default viewModel().
  • Pada fungsi GameScreen(), tambahkan variabel baru bernama gameUiState. Gunakan delegasi by dan panggil collectAsState() pada uiState.
  • Teruskan gameUiState.currentScrambledWord ke composable GameLayout(). Anda menambahkan argumen di langkah selanjutnya, jadi abaikan error untuk saat ini.
  • Tambahkan currentScrambledWord sebagai parameter lain ke fungsi composable GameLayout().
  • Perbarui fungsi composable GameLayout() untuk menampilkan currentScrambledWord. Tetapkan parameter text kolom teks pertama di kolom ke currentScrambledWord.


Menampilkan kata tebakan

  • Di file GameScreen.kt, dalam composable GameLayout(), setel onValueChange ke onUserGuessChanged dan onKeyboardDone() ke tindakan keyboard onDone. Anda dapat memperbaiki error tersebut di langkah berikutnya.
  • Pada fungsi composable GameLayout(), tambahkan dua argumen lagi: lambda onUserGuessChanged menggunakan argumen String dan tidak menampilkan apa pun, serta onKeyboardDone tidak mengambil apa pun dan tidak menampilkan apa pun.
  • Pada panggilan fungsi GameLayout(), tambahkan argumen lambda untuk onUserGuessChanged dan onKeyboardDone.
  • Di file GameViewModel.kt, tambahkan metode bernama updateUserGuess() yang menggunakan argumen String, kata tebakan pengguna. Di dalam fungsi, perbarui userGuess dengan meneruskan guessedWord.
  • Di file GameViewModel.kt, tambahkan properti var yang disebut userGuess. Gunakan mutableStateOf() agar Compose mengamati nilai ini dan menetapkan nilai awal ke "".
  • Di file GameScreen.kt, di dalam GameLayout(), tambahkan parameter String lain untuk userGuess. Tetapkan parameter value dari OutlinedTextField ke userGuess.
  • Pada fungsi GameScreen, update panggilan fungsi GameLayout() untuk menyertakan parameter userGuess

  • Jalankan app dan Coba menebak dan masukkan kata. Kolom teks dapat menampilkan tebakan pengguna.



4️⃣ Memverifikasi kata tebakan dan memperbarui skor

  • Di GameViewModel, tambahkan metode lain bernama checkUserGuess().
  • Pada fungsi checkUserGuess(), tambahkan blok if else untuk memverifikasi apakah tebakan pengguna sama dengan currentWord. Reset userGuess ke string yang kosong.
  • Jika tebakan pengguna salah, tetapkan isGuessedWordWrong ke true. MutableStateFlow<T>. update() memperbarui MutableStateFlow.value menggunakan nilai yang ditentukan.
  • Di class GameUiState, tambahkan Boolean yang disebut isGuessedWordWrong dan lakukan inisialisasi ke false.
  • Di file GameScreen.kt, di akhir fungsi composable GameScreen(), panggil gameViewModel.checkUserGuess() di dalam ekspresi lambda onClick dari tombol Submit.
  • Pada fungsi composable GameScreen(), update panggilan fungsi GameLayout() untuk meneruskan gameViewModel.checkUserGuess() dalam ekspresi lambda onKeyboardDone.
  • Pada fungsi composable GameLayout(), tambahkan parameter fungsi untuk Boolean, isGuessWrong. Tetapkan parameter isError dari OutlinedTextField ke isGuessWrong untuk menampilkan error di kolom teks jika tebakan pengguna salah.
  • Pada fungsi composable GameScreen(), update panggilan fungsi GameLayout() untuk meneruskan isGuessWrong.
  • Di file GameScreen.kt, dalam composable GameLayout(), perbarui parameter label kolom teks bergantung pada isGuessWrong

5️⃣ Memperbarui skor dan jumlah kata

  • Di GameUiState, tambahkan variabel score dan lakukan inisialisasi ke nol.
  • Untuk memperbarui nilai skor, di GameViewModel, pada fungsi checkUserGuess(), di dalam kondisi if untuk saat tebakan pengguna benar, tingkatkan nilai score.
  • Di GameViewModel, tambahkan metode lain bernama updateGameState untuk memperbarui skor, menambah jumlah kata saat ini, dan memilih kata baru dari file WordsData.kt. Tambahkan Int yang bernama updatedScore sebagai parameter. Update variabel UI status game sebagai berikut:
  • Pada fungsi checkUserGuess(), jika tebakan pengguna benar, lakukan panggilan ke updateGameState dengan skor yang telah diperbarui untuk menyiapkan game untuk putaran berikutnya.
  • Tambahkan variabel lain untuk jumlah di GameUiState. Panggil currentWordCount dan lakukan inisialisasi ke 1.
  • Di file GameViewModel.kt, pada fungsi updateGameState(), tingkatkan jumlah kata seperti yang ditunjukkan di bawah. Fungsi updateGameState() dipanggil untuk menyiapkan game untuk putaran berikutnya.
  • Di file GameScreen.kt, pada fungsi composable GameLayout(), tambahkan jumlah kata sebagai argumen dan teruskan argumen format wordCount ke elemen teks.
  • Perbarui panggilan fungsi GameLayout() untuk menyertakan jumlah kata.
  • Pada fungsi composable GameScreen(), perbarui panggilan fungsi GameStatus() untuk menyertakan parameter score. Teruskan skor dari gameUiState.
  • Di file GameScreen.kt, pada fungsi composable GameScreen(), lakukan panggilan ke gameViewModel.skipWord() dalam ekspresi lambda onClick.
  • Jalankan aplikasi Anda dan mainkan game-nya. Sekarang Anda akan dapat melewati kata.



6️⃣ Menangani putaran terakhir game

  • Di GameViewModel, tambahkan blok if-else dan pindahkan isi fungsi yang ada ke dalam blok else.
  • Tambahkan kondisi if untuk memastikan ukuran usedWords sama dengan MAX_NO_OF_WORDS.
  • Di dalam blok if, tambahkan flag Boolean isGameOver dan setel flag ke true untuk menunjukkan akhir game.
  • Perbarui score dan reset isGuessedWordWrong di dalam blok if.
  • Di GameUiState, tambahkan variabel Boolean isGameOver dan tetapkan ke false.
  • Jalankan aplikasi Anda dan mainkan game-nya. Anda tidak dapat memainkan lebih dari 10 kata.



  • Di file GameScreen.kt, pada fungsi FinalScoreDialog(), perhatikan parameter skor untuk menampilkan skor game di dialog pemberitahuan.
  • Dalam fungsi FinalScoreDialog(), perhatikan penggunaan ekspresi lambda parameter text untuk menggunakan score sebagai argumen format ke teks dialog.
  • Di file GameScreen.kt, di akhir fungsi composable GameScreen(), setelah blok Column, tambahkan kondisi if untuk memeriksa gameUiState.isGameOver.
  • Di blok if, tampilkan dialog pemberitahuan. Lakukan panggilan ke FinalScoreDialog() dengan meneruskan score dan gameViewModel.resetGame() untuk callback peristiwa onPlayAgain.
  • Dalam file GameViewModel.kt, panggil kembali fungsi resetGame(), lakukan inisialisasi _uiState, dan pilih kata baru.



7️⃣ Status dalam rotasi perangkat

  • Jalankan aplikasi dan putar beberapa kata. Ubah konfigurasi perangkat dari potret ke lanskap, atau sebaliknya.
  • Perhatikan bahwa data yang disimpan di UI status ViewModel dipertahankan selama perubahan konfigurasi.



Nilai AMAN.

ViewModel menyimpan data terkait aplikasi yang tidak dihancurkan saat framework Android menghancurkan dan membuat ulang aktivitas. Objek ViewModel secara otomatis dipertahankan dan tidak dihancurkan seperti instance aktivitas selama perubahan konfigurasi. Data yang disimpan segera tersedia setelah rekomposisi.


Dokumentasi : 


code lengkap dapat dilihat pada https://github.com/nailykhry/unscramble-ppb










Tidak ada komentar:

Posting Komentar

EAS PPB

Nama : Naily Khairiya NRP : 5025201244 Kelas : PPB - I JAWABAN EAS PPB Buat spesifikasi dan deskripsi aplikasi yang mampu dibuat berdasarkan...