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
LiveData
danMutableLiveData
di aplikasi Anda. - Cara mengenkapsulasi data yang disimpan dalam
ViewModel
denganLiveData
. - Cara menambahkan metode observer untuk mengamati perubahan di
LiveData.
- Cara menulis ekspresi binding di file tata letak.
Yang akan Anda build
- Gunakan
LiveData
untuk 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
LiveData
yang 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
:
LiveData
menyimpan data;LiveData
adalah wrapper yang dapat digunakan dengan semua jenis data.LiveData
dapat diamati, yang berarti bahwa observer akan diberi tahu saat data yang dimiliki objekLiveData
berubah.LiveData
mendukung siklus proses. Saat Anda melampirkan observer keLiveData
, observer dikaitkan denganLifecycleOwner
(biasanya berupa aktivitas atau fragmen).LiveData
hanya mengupdate observer yang dalam status siklus proses aktif sepertiSTARTED
atauRESUMED
. Anda dapat membaca info selengkapnya tentangLiveData
dan 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_currentScrambledWord
menjadiMutableLiveData
<String>
.LiveData
danMutableLiveData
adalah class generik, jadi Anda perlu menentukan jenis data yang disimpannya. - Ubah jenis variabel
_currentScrambledWord
menjadival
karena nilai objekLiveData
/MutableLiveData
akan tetap sama, dan hanya data yang disimpan dalam objek yang akan berubah.
private val _currentScrambledWord = MutableLiveData<String>()
- Ubah jenis kolom cadangan
currentScrambledWord
keLiveData<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
. DiGameViewModel
dalam metodegetNextWord()
, dalam blokelse
, ubah referensi_currentScrambledWord
menjadi_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-else
kosong 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
currentScrambledWord
LiveData
. PadaGameFragment
di 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
viewLifecycleOwner
sebagai parameter pertama ke metodeobserve()
.viewLifecycleOwner
merepresentasikan siklus proses Tampilan Fragment. Parameter ini membantuLiveData
mengetahui siklus prosesGameFragment
dan memberi tahu observer hanya jikaGameFragment
dalam status aktif (STARTED
atauRESUMED
). - Tambahkan lambda sebagai parameter kedua dengan
newWord
sebagai parameter fungsi.newWord
akan 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
newWord
ke 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_score
dan_currentWordCount
menjadival
. - Ubah jenis data variabel
_score
dan_currentWordCount
menjadiMutableLiveData
, 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
GameViewModel
pada awal metodereinitializeData()
, ubah referensi_score
dan_currentWordCount
masing-masing menjadi_score.
value
dan_currentWordCount.
value
.
fun reinitializeData() {
_score.value = 0
_currentWordCount.value = 0
wordsList.clear()
getNextWord()
}
- Di
GameViewModel
, dalam metodenextWord()
, ubah referensi_currentWordCount
menjadi_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_score
dan_currentWordCount
menjadi_score.
value
dan_currentWordCount.
value
. Android Studio akan menampilkan error karena_score
tidak 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 nilaiscore
menggunakan propertivalue
. Dalam metodeshowFinalScoreDialog()
, ubahviewModel.score
menjadiviewModel.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
GameFragment
dalam 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
GameFragment
di akhir metodeonViewCreated()
, lampirkan observer untukscore
. TeruskanviewLifecycleOwner
sebagai 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 untukcurrentWordCount
LiveData
. TeruskanviewLifecycleOwner
sebagai 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_WORDS
pada 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.
score
dancurrentWordCount
adalahLiveData
dan 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 propertidataBinding
pada 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 variabelbinding
untuk 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 disebutgameViewModel
dan jenisGameViewModel
. Anda akan menggunakannya untuk mengikat data diViewModel
ke 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
GameFragment
di awal metodeonViewCreated()
, inisialisasi variabel tata letakgameViewModel
danmaxNoOfWords
.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.gameViewModel = viewModel
binding.maxNoOfWords = MAX_NO_OF_WORDS
...
}
LiveData
dapat 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 atributtext
ke tampilan tekstextView_unscrambled_word
. Gunakan variabel tata letak baru,gameViewModel
dan tetapkan@{gameViewModel.currentScrambledWord}
ke atributtext
.
<TextView
android:id="@+id/textView_unscrambled_word"
...
android:text="@{gameViewModel.currentScrambledWord}"
.../>
- Di
GameFragment
, hapus kode observerLiveData
untukcurrentScrambledWord
: Anda tidak memerlukan kode observer dalam fragmen lagi. Tata letak ini menerima pembaruan perubahan padaLiveData
secara 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 atributtext
untuk tampilan teksword_count
dengan ekspresi binding berikut. Gunakan resource stringword_count
dan masukkan dalamgameViewModel.currentWordCount
, danmaxNoOfWords
sebagai parameter resource.
<TextView
android:id="@+id/word_count"
...
android:text="@{@string/word_count(gameViewModel.currentWordCount, maxNoOfWords)}"
.../>
- Perbarui atribut
text
untuk tampilan teksscore
dengan ekspresi binding berikut. Gunakan resource stringscore
dan teruskangameViewModel.score
sebagai parameter resource.
<TextView
android:id="@+id/score"
...
android:text="@{@string/score(gameViewModel.score)}"
... />
- Hapus observer
LiveData
dariGameFragment
. Anda tidak membutuhkannya lagi, ekspresi binding akan mengupdate UI saatLiveData
yang 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
LiveData
dan 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 acakString
menjadi stringSpannable
. String spannable adalah string yang berisi beberapa informasi tambahan. Dalam hal ini, kita ingin mengaitkan string denganTtsSpan
dariTYPE_VERBATIM
, sehingga mesin text-to-speech membaca kata acak secara jelas dan lantang, karakter demi karakter. - Di
GameViewModel
, gunakan kode berikut untuk mengubah cara variabelcurrentScrambledWord
dideklarasikan:
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
Log
dalam file sumber (GameFragment.kt
danGameViewModel.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
LiveData
menyimpan data;LiveData
adalah wrapper yang dapat digunakan dengan data apa punLiveData
dapat diamati, yang berarti bahwa observer akan diberi tahu saat data yang dimiliki objekLiveData
berubah.LiveData
mendukung siklus proses. Saat Anda melampirkan observer keLiveData
, observer dikaitkan denganLifecycleOwner
(biasanya Activity atau Fragment). LiveData hanya mengupdate observer yang dalam status siklus proses aktif sepertiSTARTED
atauRESUMED
. Anda dapat membaca info selengkapnya tentangLiveData
dan 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