1. Sebelum memulai
Anda telah mempelajari di codelab sebelumnya cara menggunakan ViewModel untuk menyimpan data aplikasi. ViewModel memungkinkan data aplikasi bertahan saat terjadi perubahan konfigurasi. Dalam codelab ini, Anda akan mempelajari cara mengintegrasikan LiveData dengan data di ViewModel.
Class LiveData juga merupakan bagian dari Komponen Arsitektur Android dan merupakan class holder data yang dapat diamati.
Prasyarat
- Cara mendownload kode sumber dari GitHub dan membukanya di Android Studio.
- Cara membuat dan menjalankan aplikasi Android dasar di Kotlin, dengan menggunakan aktivitas dan fragmen.
- Cara kerja siklus proses aktivitas dan fragmen.
- Cara mempertahankan data UI melalui perubahan konfigurasi perangkat menggunakan
ViewModel. - Cara menulis ekspresi lambda.
Yang akan Anda pelajari
- Cara menggunakan
LiveDatadanMutableLiveDatadi aplikasi Anda. - Cara mengenkapsulasi data yang disimpan dalam
ViewModeldenganLiveData. - Cara menambahkan metode observer untuk mengamati perubahan di
LiveData. - Cara menulis ekspresi binding di file tata letak.
Yang akan Anda build
- Gunakan
LiveDatauntuk data aplikasi (kata, jumlah kata, dan skor) di aplikasi Unscramble. - Tambahkan metode observer yang mendapatkan notifikasi saat data berubah, perbarui tampilan teks kata acak secara otomatis.
- Tulis ekspresi binding dalam file tata letak, yang dipicu saat
LiveDatayang mendasarinya diubah. Skor, jumlah kata, dan tampilan teks kata yang diacak diperbarui secara otomatis.
Yang Anda perlukan
- Komputer yang dilengkapi Android Studio.
- Kode solusi dari codelab sebelumnya (aplikasi Unscramble dengan
ViewModel).
Mendownload kode awal untuk codelab ini
Codelab ini menggunakan aplikasi Unscramble yang Anda build di codelab sebelumnya (Menyimpan data di ViewModel) sebagai kode awal.
2. Ringkasan aplikasi awal
Codelab ini menggunakan kode solusi Unscramble yang Anda kenal dari codelab sebelumnya. Aplikasi menampilkan kata acak untuk disusun ulang oleh pemain. Pemain dapat mencoba beberapa kali untuk menebak kata yang benar. Data aplikasi seperti kata saat ini, skor pemain, dan jumlah kata akan disimpan di ViewModel. Namun, UI aplikasi tidak mencerminkan nilai skor dan nilai jumlah kata yang baru. Dalam codelab ini, Anda akan menerapkan fitur yang hilang menggunakan LiveData.

3. Apa yang dimaksud dengan Livedata
LiveData adalah class holder data yang dapat diamati dan peka terhadap siklus proses.
Beberapa karakteristik LiveData:
LiveDatamenyimpan data;LiveDataadalah wrapper yang dapat digunakan dengan semua jenis data.LiveDatadapat diamati, yang berarti bahwa observer akan diberi tahu saat data yang dimiliki objekLiveDataberubah.LiveDatamendukung siklus proses. Saat Anda melampirkan observer keLiveData, observer dikaitkan denganLifecycleOwner(biasanya berupa aktivitas atau fragmen).LiveDatahanya mengupdate observer yang dalam status siklus proses aktif sepertiSTARTEDatauRESUMED. Anda dapat membaca info selengkapnya tentangLiveDatadan observasi di sini.
Proses update UI di kode awal
Dalam kode awal, metode updateNextWordOnScreen() dipanggil secara eksplisit, setiap kali Anda ingin menampilkan kata acak baru di UI. Anda memanggil metode ini selama inisialisasi game, dan saat pemain menekan tombol Submit atau Skip. Metode ini dipanggil dari metode onViewCreated(), restartGame(), onSkipWord(), dan onSubmitWord(). Dengan Livedata, Anda tidak perlu memanggil metode ini dari beberapa tempat untuk mengupdate UI. Anda hanya akan melakukannya sekali di observer.
4. Menambahkan LiveData ke kata acak saat ini
Dalam tugas ini, Anda akan mempelajari cara menggabungkan data dengan LiveData, dengan mengonversi kata saat ini di GameViewModel menjadi LiveData. Pada tugas selanjutnya, Anda akan menambahkan observer ke objek LiveData ini dan mempelajari cara mengobservasi LiveData.
MutableLiveData
MutableLiveData adalah versi LiveData yang bisa berubah, yaitu, nilai data yang tersimpan di dalamnya dapat diubah.
- Di
GameViewModel, ubah jenis variabel_currentScrambledWordmenjadiMutableLiveData<String>.LiveDatadanMutableLiveDataadalah class generik, jadi Anda perlu menentukan jenis data yang disimpannya. - Ubah jenis variabel
_currentScrambledWordmenjadivalkarena nilai objekLiveData/MutableLiveDataakan tetap sama, dan hanya data yang disimpan dalam objek yang akan berubah.
private val _currentScrambledWord = MutableLiveData<String>()
- Ubah jenis kolom cadangan
currentScrambledWordkeLiveData<String>, karena tidak dapat diubah. Android Studio akan menampilkan beberapa error yang akan Anda perbaiki pada langkah berikutnya.
val currentScrambledWord: LiveData<String>
get() = _currentScrambledWord
- Untuk mengakses data dalam objek
LiveData, gunakan propertivalue. DiGameViewModeldalam metodegetNextWord(), dalam blokelse, ubah referensi_currentScrambledWordmenjadi_currentScrambledWord.value.
private fun getNextWord() {
...
} else {
_currentScrambledWord.value = String(tempWord)
...
}
}
5. Melampirkan observer ke objek LiveData
Dalam tugas ini, Anda menyiapkan observer di komponen aplikasi, GameFragment. Observer yang akan Anda tambahkan mengobservasi perubahan pada data aplikasi currentScrambledWord. LiveData berbasis siklus proses, yang berarti hanya mengupdate observer yang ada dalam status siklus proses aktif. Jadi, observer dalam GameFragment hanya akan diberi tahu jika GameFragment dalam status STARTED atau RESUMED.
- Di
GameFragment, hapus metodeupdateNextWordOnScreen()dan semua panggilan ke dalamnya. Anda tidak memerlukan metode ini, karena Anda akan melampirkan observer keLiveData. - Di
onSubmitWord(), ubah blokif-elsekosong sebagai berikut. Metode yang lengkap akan terlihat seperti ini.
private fun onSubmitWord() {
val playerWord = binding.textInputEditText.text.toString()
if (viewModel.isUserWordCorrect(playerWord)) {
setErrorTextField(false)
if (!viewModel.nextWord()) {
showFinalScoreDialog()
}
} else {
setErrorTextField(true)
}
}
- Lampirkan observer untuk
currentScrambledWordLiveData. PadaGameFragmentdi akhir callbackonViewCreated(), panggil metodeobserve()padacurrentScrambledWord.
// Observe the currentScrambledWord LiveData.
viewModel.currentScrambledWord.observe()
Android Studio akan menampilkan error tentang parameter yang tidak ada. Anda akan memperbaiki error tersebut di langkah berikutnya.
- Teruskan
viewLifecycleOwnersebagai parameter pertama ke metodeobserve().viewLifecycleOwnermerepresentasikan siklus proses Tampilan Fragment. Parameter ini membantuLiveDatamengetahui siklus prosesGameFragmentdan memberi tahu observer hanya jikaGameFragmentdalam status aktif (STARTEDatauRESUMED). - Tambahkan lambda sebagai parameter kedua dengan
newWordsebagai parameter fungsi.newWordakan berisi nilai kata acak yang baru.
// Observe the scrambledCharArray LiveData, passing in the LifecycleOwner and the observer.
viewModel.currentScrambledWord.observe(viewLifecycleOwner,
{ newWord ->
})
Ekspresi lambda adalah fungsi anonim yang tidak dideklarasikan, tetapi langsung diteruskan sebagai ekspresi. Ekspresi lambda selalu dikelilingi oleh tanda kurung kurawal { }.
- Dalam isi fungsi ekspresi lambda, tetapkan
newWordke tampilan teks kata acak.
// Observe the scrambledCharArray LiveData, passing in the LifecycleOwner and the observer.
viewModel.currentScrambledWord.observe(viewLifecycleOwner,
{ newWord ->
binding.textViewUnscrambledWord.text = newWord
})
- Kompilasi dan jalankan aplikasi. Aplikasi game Anda seharusnya bekerja persis seperti sebelumnya, tetapi sekarang tampilan teks kata acak akan diperbarui secara otomatis di observer
LiveData, bukan di metodeupdateNextWordOnScreen().
6. Memasang observer ke skor dan jumlah kata
Seperti pada tugas sebelumnya, dalam tugas ini, Anda akan menambahkan LiveData ke data lain di aplikasi, skor, dan jumlah kata, sehingga UI diupdate dengan nilai skor dan jumlah kata yang benar selama game.
Langkah 1: Gabungkan skor dan jumlah kata dengan LiveData
- Dalam
GameViewModel, ubah jenis variabel class_scoredan_currentWordCountmenjadival. - Ubah jenis data variabel
_scoredan_currentWordCountmenjadiMutableLiveData, lalu inisialisasikan ke0. - Ubah jenis kolom cadangan ke
LiveData<Int>.
private val _score = MutableLiveData(0)
val score: LiveData<Int>
get() = _score
private val _currentWordCount = MutableLiveData(0)
val currentWordCount: LiveData<Int>
get() = _currentWordCount
- Di
GameViewModelpada awal metodereinitializeData(), ubah referensi_scoredan_currentWordCountmasing-masing menjadi_score.valuedan_currentWordCount.value.
fun reinitializeData() {
_score.value = 0
_currentWordCount.value = 0
wordsList.clear()
getNextWord()
}
- Di
GameViewModel, dalam metodenextWord(), ubah referensi_currentWordCountmenjadi_currentWordCount.value!!.
fun nextWord(): Boolean {
return if (_currentWordCount.value!! < MAX_NO_OF_WORDS) {
getNextWord()
true
} else false
}
- Di
GameViewModel, di dalam metodeincreaseScore()dangetNextWord(), ubah referensi_scoredan_currentWordCountmenjadi_score.valuedan_currentWordCount.value. Android Studio akan menampilkan error karena_scoretidak lagi berupa bilangan bulat, namunLiveData, dan Anda akan memperbaikinya di langkah berikutnya. - Gunakan fungsi Kotlin
plus()untuk meningkatkan nilai_score, yang menjalankan penambahan dengan keamanan null.
private fun increaseScore() {
_score.value = (_score.value)?.plus(SCORE_INCREASE)
}
- Demikian pula, gunakan fungsi Kotlin
inc()untuk meningkatkan nilai satu per satu dengan keamanan null.
private fun getNextWord() {
...
} else {
_currentScrambledWord.value = String(tempWord)
_currentWordCount.value = (_currentWordCount.value)?.inc()
wordsList.add(currentWord)
}
}
- Di
GameFragment, akses nilaiscoremenggunakan propertivalue. Dalam metodeshowFinalScoreDialog(), ubahviewModel.scoremenjadiviewModel.score.value.
private fun showFinalScoreDialog() {
MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.congratulations))
.setMessage(getString(R.string.you_scored, viewModel.score.value))
...
.show()
}
Langkah 2: Lampirkan observer ke skor dan jumlah kata
Di aplikasi, skor dan jumlah kata tidak diperbarui. Anda akan memperbaruinya dalam tugas ini menggunakan observer LiveData.
- Di
GameFragmentdalam metodeonViewCreated(), hapus kode yang memperbarui tampilan teks skor dan jumlah kata.
Hapus:
binding.score.text = getString(R.string.score, 0)
binding.wordCount.text = getString(R.string.word_count, 0, MAX_NO_OF_WORDS)
- Pada
GameFragmentdi akhir metodeonViewCreated(), lampirkan observer untukscore. TeruskanviewLifecycleOwnersebagai parameter pertama ke observer dan ekspresi lambda untuk parameter kedua. Di dalam ekspresi lambda, teruskan skor baru sebagai parameter dan di dalam isi fungsi, setel skor baru ke tampilan teks.
viewModel.score.observe(viewLifecycleOwner,
{ newScore ->
binding.score.text = getString(R.string.score, newScore)
})
- Di akhir metode
onViewCreated(), lampirkan observer untukcurrentWordCountLiveData. TeruskanviewLifecycleOwnersebagai parameter pertama ke observer dan ekspresi lambda untuk parameter kedua. Di dalam ekspresi lambda, teruskan jumlah kata baru sebagai parameter dan di isi fungsi, tetapkan jumlah kata baru denganMAX_NO_OF_WORDSpada tampilan teks.
viewModel.currentWordCount.observe(viewLifecycleOwner,
{ newWordCount ->
binding.wordCount.text =
getString(R.string.word_count, newWordCount, MAX_NO_OF_WORDS)
})
Observer baru akan dipicu saat nilai skor dan jumlah kata diubah di dalam ViewModel, selama masa pakai pemilik siklus proses, yaitu, GameFragment.
- Jalankan aplikasi Anda untuk melihat keajaibannya. Mainkan game dengan beberapa kata. Skor dan jumlah kata juga diperbarui dengan benar di layar. Perhatikan bahwa Anda tidak memperbarui tampilan teks ini berdasarkan beberapa kondisi dalam kode.
scoredancurrentWordCountadalahLiveDatadan observer yang sesuai secara otomatis dipanggil saat nilai yang mendasarinya berubah.

7. Menggunakan LiveData dengan data binding
Pada tugas sebelumnya, aplikasi Anda memproses perubahan data dalam kode. Demikian pula, aplikasi dapat memproses perubahan data dari tata letak. Dengan Data Binding, saat nilai LiveData yang dapat diobservasi berubah, elemen UI dalam tata letak yang terikat juga akan diberi tahu, dan UI dapat diperbarui dari dalam tata letak.
Konsep: Data binding
Dalam codelab sebelumnya, Anda telah melihat View Binding, yang merupakan binding satu arah. Anda dapat mengikat tampilan ke kode namun tidak sebaliknya.
Mengingat kembali View binding:
View binding adalah fitur yang memungkinkan Anda mengakses tampilan dalam kode dengan lebih mudah. Ini menghasilkan class binding untuk setiap file tata letak XML. Instance class binding berisi referensi langsung ke semua tampilan yang memiliki ID di tata letak yang terkait. Misalnya, aplikasi Unscramble saat ini menggunakan view binding, sehingga tampilan dapat direferensikan dalam kode menggunakan class binding yang dihasilkan.
Contoh:
binding.textViewUnscrambledWord.text = newWord
binding.score.text = getString(R.string.score, newScore)
binding.wordCount.text =
getString(R.string.word_count, newWordCount, MAX_NO_OF_WORDS)
Dengan menggunakan view binding, Anda tidak dapat mereferensikan data aplikasi dalam tampilan (file tata letak). Hal ini dapat dilakukan menggunakan Data binding.
Data Binding
Library Data Binding juga merupakan bagian dari library Android Jetpack. Data binding mengikat komponen UI dalam tata letak ke sumber data dalam aplikasi menggunakan format deklaratif, yang akan Anda pelajari nanti dalam codelab.
Dalam istilah yang lebih sederhana, Data binding adalah mengikat data (dari kode) ke tampilan + view binding (mengikat tampilan ke kode):
Contoh menggunakan view binding di pengontrol UI
binding.textViewUnscrambledWord.text = viewModel.currentScrambledWord
Contoh menggunakan data binding dalam file tata letak
android:text="@{gameViewModel.currentScrambledWord}"
Contoh di atas menampilkan cara menggunakan Library Data Binding untuk menetapkan data aplikasi ke tampilan/widget secara langsung dalam file tata letak. Perhatikan penggunaan sintaksis @{} dalam ekspresi penetapan.
Keuntungan utama dari penggunaan data binding adalah, Anda dapat menghapus banyak panggilan framework UI dalam aktivitas, yang menjadikannya lebih sederhana dan lebih mudah dikelola. Hal ini juga dapat meningkatkan performa aplikasi Anda dan membantu mencegah kebocoran memori dan pengecualian pointer null.
Langkah 1: Ubah view binding ke data binding
- Di file
build.gradle(Module), aktifkan propertidataBindingpada bagianbuildFeatures.
Ganti
buildFeatures {
viewBinding = true
}
dengan
buildFeatures {
dataBinding = true
}
Lakukan sinkronisasi gradle saat diminta oleh Android Studio.
- Untuk menggunakan data binding di project Kotlin, Anda harus menerapkan plugin
kotlin-kapt. Langkah ini sudah dilakukan untuk Anda di filebuild.gradle(Module).
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
Langkah di atas otomatis menghasilkan class binding untuk setiap file XML tata letak dalam aplikasi. Jika nama file tata letak adalah activity_main.xml maka class autogen akan disebut ActivityMainBinding.
Langkah 2: Konversikan file tata letak menjadi tata letak data binding
File tata letak data binding sedikit berbeda dan dimulai dengan tag root dari <layout> diikuti dengan elemen <data> opsional dan elemen root view. Di elemen tampilan inilah root Anda akan berada dalam file tata letak non-binding.
- Buka
game_fragment.xml, pilih tab code. - Untuk mengonversi tata letak ke tata letak Data Binding, gabungkan elemen root dalam tag
<layout>. Anda juga harus memindahkan definisi namespace (atribut yang dimulai denganxmlns:) ke elemen root baru. Tambahkan tag<data></data>di dalam tag<layout>di atas elemen root. Android Studio menawarkan cara praktis untuk melakukannya secara otomatis: Klik kanan elemen root (ScrollView), pilih Show Context Actions > Convert to data binding layout.

- Tata letak Anda akan terlihat seperti ini:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
...
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</layout>
- Di
GameFragment, pada awal metodeonCreateView(), ubah pembuatan instance variabelbindinguntuk menggunakan data binding.
Ganti
binding = GameFragmentBinding.inflate(inflater, container, false)
dengan
binding = DataBindingUtil.inflate(inflater, R.layout.game_fragment, container, false)
- Kompilasi kodenya; seharusnya Anda dapat mengompilasi tanpa masalah apa pun. Aplikasi Anda sekarang menggunakan data binding dan tampilan di tata letak dapat mengakses data aplikasi.
8. Menambahkan variabel data binding
Dalam tugas ini, Anda akan menambahkan properti di file tata letak untuk mengakses data aplikasi dari viewModel. Anda akan melakukan inisialisasi variabel tata letak dalam kode.
- Di
game_fragment.xml, di dalam tag<data>, tambahkan tag turunan yang disebut<variable>, deklarasikan properti yang disebutgameViewModeldan jenisGameViewModel. Anda akan menggunakannya untuk mengikat data diViewModelke tata letak.
<data>
<variable
name="gameViewModel"
type="com.example.android.unscramble.ui.game.GameViewModel" />
</data>
Perhatikan bahwa jenis gameViewModel berisi nama paket. Pastikan nama paket ini cocok dengan nama paket di aplikasi Anda.
- Di bawah deklarasi
gameViewModel, tambahkan variabel lain di dalam tag<data>jenisInteger, dan beri namamaxNoOfWords. Anda akan menggunakan ini untuk mengikat ke variabel di ViewModel guna menyimpan jumlah kata per game.
<data>
...
<variable
name="maxNoOfWords"
type="int" />
</data>
- Pada
GameFragmentdi awal metodeonViewCreated(), inisialisasi variabel tata letakgameViewModeldanmaxNoOfWords.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.gameViewModel = viewModel
binding.maxNoOfWords = MAX_NO_OF_WORDS
...
}
LiveDatadapat diobservasi oleh siklus proses, jadi Anda harus meneruskan pemilik siklus proses ke tata letak. PadaGameFragment, di dalam metodeonViewCreated(), di bawah inisialisasi variabel binding, tambahkan kode berikut.
// Specify the fragment view as the lifecycle owner of the binding.
// This is used so that the binding can observe LiveData updates
binding.lifecycleOwner = viewLifecycleOwner
Ingatlah bahwa Anda menerapkan fungsi serupa saat menerapkan observer LiveData. Anda meneruskan viewLifecycleOwner sebagai salah satu parameter ke observer LiveData.
9. Menggunakan ekspresi binding
Ekspresi binding ditulis dalam tata letak di properti atribut (seperti android:text) yang mereferensikan properti tata letak. Properti tata letak dideklarasikan di bagian atas file tata letak data binding, melalui tag <variable>. Saat salah satu variabel dependen berubah, ‘DB Library’ akan menjalankan ekspresi binding Anda (sehingga memperbarui tampilan). Deteksi perubahan ini adalah pengoptimalan hebat yang Anda dapatkan secara cuma-cuma, saat menggunakan Library Data Binding.
Sintaksis untuk ekspresi binding
Ekspresi binding dimulai dengan simbol @ dan diletakkan di tengah dua tanda kurung kurawal {}. Pada contoh berikut, teks TextView disetel ke properti firstName variabel user:
Contoh:
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}" />
Langkah 1: Tambahkan ekspresi binding ke kata saat ini
Pada langkah ini, Anda mengikat tampilan teks kata saat ini ke objek LiveData di ViewModel.
- Di
game_fragment.xml, tambahkan atributtextke tampilan tekstextView_unscrambled_word. Gunakan variabel tata letak baru,gameViewModeldan tetapkan@{gameViewModel.currentScrambledWord}ke atributtext.
<TextView
android:id="@+id/textView_unscrambled_word"
...
android:text="@{gameViewModel.currentScrambledWord}"
.../>
- Di
GameFragment, hapus kode observerLiveDatauntukcurrentScrambledWord: Anda tidak memerlukan kode observer dalam fragmen lagi. Tata letak ini menerima pembaruan perubahan padaLiveDatasecara langsung.
Hapus:
viewModel.currentScrambledWord.observe(viewLifecycleOwner,
{ newWord ->
binding.textViewUnscrambledWord.text = newWord
})
- Jalankan aplikasi Anda, aplikasi seharusnya berfungsi seperti sebelumnya. Namun, kini tampilan teks kata yang diacak menggunakan ekspresi binding untuk mengupdate UI, bukan observer
LiveData.
Langkah 2: Tambahkan ekspresi binding ke skor dan jumlah kata
Resource dalam ekspresi data binding
Ekspresi data binding dapat mereferensikan resource aplikasi dengan sintaksis berikut.
Contoh:
android:padding="@{@dimen/largePadding}"
Pada contoh di atas, atribut padding diberi nilai largePadding dari file resource dimen.xml.
Anda juga dapat meneruskan properti tata letak sebagai parameter resource.
Contoh:
android:text="@{@string/example_resource(user.lastName)}"
strings.xml
<string name="example_resource">Last Name: %s</string>
Pada contoh di atas, example_resource adalah resource string dengan placeholder %s. Anda meneruskan user.lastName sebagai parameter resource dalam ekspresi binding, dengan user yang merupakan variabel tata letak.
Pada langkah ini, Anda akan menambahkan ekspresi binding ke tampilan teks skor dan jumlah kata, dengan meneruskan parameter resource. Langkah ini mirip dengan langkah yang Anda lakukan untuk textView_unscrambled_word di atas.
- Di
game_fragment.xml, perbarui atributtextuntuk tampilan teksword_countdengan ekspresi binding berikut. Gunakan resource stringword_countdan masukkan dalamgameViewModel.currentWordCount, danmaxNoOfWordssebagai parameter resource.
<TextView
android:id="@+id/word_count"
...
android:text="@{@string/word_count(gameViewModel.currentWordCount, maxNoOfWords)}"
.../>
- Perbarui atribut
textuntuk tampilan teksscoredengan ekspresi binding berikut. Gunakan resource stringscoredan teruskangameViewModel.scoresebagai parameter resource.
<TextView
android:id="@+id/score"
...
android:text="@{@string/score(gameViewModel.score)}"
... />
- Hapus observer
LiveDatadariGameFragment. Anda tidak membutuhkannya lagi, ekspresi binding akan mengupdate UI saatLiveDatayang sesuai berubah.
Hapus:
viewModel.score.observe(viewLifecycleOwner,
{ newScore ->
binding.score.text = getString(R.string.score, newScore)
})
viewModel.currentWordCount.observe(viewLifecycleOwner,
{ newWordCount ->
binding.wordCount.text =
getString(R.string.word_count, newWordCount, MAX_NO_OF_WORDS)
})
- Jalankan aplikasi dan mainkan beberapa kata. Sekarang kode Anda menggunakan
LiveDatadan ekspresi binding untuk mengupdate UI.

Selamat! Anda telah mempelajari cara menggunakan LiveData dengan observer LiveData dan LiveData dengan ekspresi binding.
10. Menguji aplikasi Unscramble dengan Talkback diaktifkan
Seperti yang telah Anda pelajari selama kursus ini, Anda ingin mem-build aplikasi yang bisa diakses oleh sebanyak mungkin pengguna. Beberapa pengguna mungkin menggunakan Talkback untuk mengakses dan menavigasi aplikasi Anda. TalkBack adalah pembaca layar Google yang disertakan di perangkat Android. TalkBack memberikan respons lisan sehingga Anda dapat menggunakan perangkat tanpa melihat layar.
Jika Talkback aktif, pastikan pemain bisa memainkan game.
- Aktifkan Talkback di perangkat Anda dengan mengikuti petunjuk ini.
- Kembali ke aplikasi Unscramble.
- Jelajahi aplikasi Anda dengan Talkback menggunakan petunjuk ini. Geser ke kanan untuk menavigasi elemen layar secara berurutan, dan geser ke kiri untuk beralih ke arah yang berlawanan. Ketuk dua kali di mana saja untuk memilih. Verifikasi bahwa Anda dapat menjangkau semua elemen aplikasi dengan gestur geser.
- Pastikan bahwa pengguna Talkback dapat menavigasi ke setiap item di layar.
- Perhatikan bahwa Talkback mencoba membaca kata acak sebagai kata. Hal ini dapat membingungkan pemain karena ini bukan kata sebenarnya.
- Pengalaman pengguna yang lebih baik adalah membuat Talkback membacakan dengan keras setiap karakter dari kata yang diacak. Dalam
GameViewModel, konversikan kata acakStringmenjadi stringSpannable. String spannable adalah string yang berisi beberapa informasi tambahan. Dalam hal ini, kita ingin mengaitkan string denganTtsSpandariTYPE_VERBATIM, sehingga mesin text-to-speech membaca kata acak secara jelas dan lantang, karakter demi karakter. - Di
GameViewModel, gunakan kode berikut untuk mengubah cara variabelcurrentScrambledWorddideklarasikan:
val currentScrambledWord: LiveData<Spannable> = Transformations.map(_currentScrambledWord) {
if (it == null) {
SpannableString("")
} else {
val scrambledWord = it.toString()
val spannable: Spannable = SpannableString(scrambledWord)
spannable.setSpan(
TtsSpan.VerbatimBuilder(scrambledWord).build(),
0,
scrambledWord.length,
Spannable.SPAN_INCLUSIVE_INCLUSIVE
)
spannable
}
}
Variabel ini sekarang menjadi LiveData<Spannable> bukan LiveData<String>. Anda tidak perlu khawatir jika belum memahami semua detail cara kerjanya, tetapi yang pasti penerapannya menggunakan transformasi LiveData untuk mengonversi kata acak String saat ini menjadi string Spannable yang dapat ditangani dengan tepat oleh layanan aksesibilitas. Pada codelab berikutnya, Anda akan mempelajari lebih lanjut transformasi LiveData, yang memungkinkan Anda menampilkan instance LiveData yang berbeda berdasarkan nilai LiveData yang sesuai.
- Jalankan aplikasi Unscramble, jelajahi aplikasi dengan Talkback. TalkBack seharusnya membacakan setiap karakter dari kata yang diacak sekarang.
Untuk informasi selengkapnya tentang cara membuat aplikasi lebih mudah diakses, lihat prinsip ini.
11. Menghapus kode yang tidak digunakan
Praktik yang baik untuk dilakukan adalah menghapus kode mati, tidak terpakai, dan tidak diinginkan untuk kode solusi. Hal ini membuat kode mudah dikelola, yang juga memudahkan rekan tim baru untuk memahami kode dengan lebih baik.
- Dalam
GameFragment, hapus metodegetNextScrambledWord()danonDetach(). - Dalam
GameViewModel, hapus metodeonCleared(). - Hapus semua impor yang tidak digunakan, di bagian atas file sumber. Nantinya impor tersebut akan berwarna abu-abu.
Anda tidak memerlukan laporan log lagi. Anda dapat menghapusnya dari kode jika perlu.
- [Opsional] Hapus pernyataan
Logdalam file sumber (GameFragment.ktdanGameViewModel.kt) yang Anda tambahkan di codelab sebelumnya, untuk memahami siklus prosesViewModel.
12. Kode solusi
Kode solusi untuk codelab ini ada dalam project yang ditampilkan di bawah.
- Buka halaman repositori GitHub yang disediakan untuk project.
- Pastikan nama cabang cocok dengan nama cabang yang ditentukan dalam codelab. Misalnya, dalam screenshot berikut, nama cabang adalah main (utama).

- Di halaman GitHub project, klik tombol Code yang akan menampilkan pop-up.

- Pada pop-up, klik tombol Download ZIP untuk menyimpan project di komputer. Tunggu download selesai.
- Temukan file di komputer Anda (mungkin di folder Downloads).
- Klik dua kali pada file ZIP untuk mengekstraknya. Tindakan ini akan membuat folder baru yang berisi file project.
Membuka project di Android Studio
- Mulai Android Studio.
- Di jendela Welcome to Android Studio, klik Open.

Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > Open.

- Di file browser, buka lokasi folder project yang telah diekstrak (kemungkinan ada di folder Downloads).
- Klik dua kali pada folder project tersebut.
- Tunggu Android Studio membuka project.
- Klik tombol Run
untuk mem-build dan menjalankan aplikasi. Pastikan aplikasi di-build seperti yang diharapkan.
13. Ringkasan
LiveDatamenyimpan data;LiveDataadalah wrapper yang dapat digunakan dengan data apa punLiveDatadapat diamati, yang berarti bahwa observer akan diberi tahu saat data yang dimiliki objekLiveDataberubah.LiveDatamendukung siklus proses. Saat Anda melampirkan observer keLiveData, observer dikaitkan denganLifecycleOwner(biasanya Activity atau Fragment). LiveData hanya mengupdate observer yang dalam status siklus proses aktif sepertiSTARTEDatauRESUMED. Anda dapat membaca info selengkapnya tentangLiveDatadan observasi di sini.- Aplikasi dapat memproses perubahan LiveData dari tata letak menggunakan Data Binding dan ekspresi binding.
- Ekspresi binding ditulis dalam tata letak di properti atribut (seperti
android:text) yang mereferensikan properti tata letak.
14. Mempelajari lebih lanjut
- Ringkasan LiveData
- Referensi API observer LiveData
- Data binding
- Data binding dua arah
Postingan blog