Codelab ini adalah bagian dari kursus Dasar-Dasar Kotlin Android. Anda akan mendapatkan manfaat maksimal dari kursus ini jika Anda mengerjakan codelab secara berurutan. Semua codelab kursus tercantum di halaman landing codelab Dasar-Dasar Android Kotlin.
Pengantar
Pada codelab sebelumnya di tutorial ini, Anda meningkatkan kode untuk aplikasi GuessTheWord. Aplikasi ini sekarang menggunakan objek ViewModel
, sehingga data aplikasi bertahan dari perubahan konfigurasi perangkat seperti rotasi layar dan perubahan ketersediaan keyboard. Anda juga menambahkan LiveData
yang dapat diamati, sehingga tampilan akan otomatis diberi tahu saat data yang diamati berubah.
Dalam codelab ini, Anda terus menggunakan aplikasi GuessTheWord. Anda mengikat tampilan ke class ViewModel
di aplikasi sehingga tampilan di tata letak Anda berkomunikasi langsung dengan objek ViewModel
. (Sampai sekarang di aplikasi Anda, tampilan telah berkomunikasi secara tidak langsung dengan ViewModel
, melalui fragmen aplikasi.) Setelah mengintegrasikan data binding dengan objek ViewModel
, Anda tidak lagi memerlukan pengendali klik di fragmen aplikasi, sehingga Anda menghapusnya.
Anda juga mengubah aplikasi GuessTheWord untuk menggunakan LiveData
sebagai sumber data binding untuk memberi tahu UI tentang perubahan data, tanpa menggunakan metode observer LiveData
.
Yang harus sudah Anda ketahui
- Cara membuat aplikasi Android dasar di Kotlin.
- Cara kerja siklus proses aktivitas dan fragmen.
- Cara menggunakan objek
ViewModel
di aplikasi Anda. - Cara menyimpan data menggunakan
LiveData
diViewModel
. - Cara menambahkan metode observer untuk mengamati perubahan dalam data
LiveData
.
Yang akan Anda pelajari
- Cara menggunakan elemen Library Data Binding.
- Cara mengintegrasikan
ViewModel
dengan data binding. - Cara mengintegrasikan
LiveData
dengan data binding. - Cara menggunakan binding pemroses untuk menggantikan pemroses klik dalam fragmen.
- Cara menambahkan pemformatan string ke ekspresi data binding.
Yang akan Anda lakukan
- Tampilan di tata letak GuessTheWord berkomunikasi secara tidak langsung dengan objek
ViewModel
, menggunakan pengontrol UI (fragmen) untuk menyampaikan informasi. Dalam codelab ini, Anda mengikat tampilan aplikasi ke objekViewModel
sehingga tampilan berkomunikasi secara langsung dengan objekViewModel
. - Anda mengubah aplikasi untuk menggunakan
LiveData
sebagai sumber data binding. Setelah perubahan ini, objekLiveData
akan memberi tahu UI tentang perubahan dalam data, dan metode pengamatLiveData
tidak lagi diperlukan.
Dalam codelab Tutorial 5, Anda mengembangkan aplikasi GuessTheWord, dimulai dengan kode awal. GuessTheWord adalah game bergaya charade dua pemain, tempat pemain berkolaborasi untuk mencapai skor tertinggi.
Pemain pertama melihat kata dalam aplikasi dan memainkannya satu per satu, sehingga dia tidak akan menampilkan kata tersebut ke pemain kedua. Pemain kedua mencoba menebak kata.
Untuk memainkan game, pemain pertama membuka aplikasi di perangkat dan melihat kata, misalnya "gitar," seperti yang ditunjukkan pada screenshot di bawah ini.
Pemain pertama akan memainkannya, berhati-hatilah untuk tidak benar-benar mengucapkan kata itu sendiri.
- Saat pemain kedua menebak kata dengan benar, pemain pertama menekan tombol Oke, yang akan meningkatkan jumlah satu kata dan menampilkan kata berikutnya.
- Jika pemain kedua tidak dapat menebak kata, pemain pertama menekan tombol Lewati, yang mengurangi jumlah satu dan melewati ke kata berikutnya.
- Untuk mengakhiri game, tekan tombol End Game. (Fungsi ini tidak ada dalam kode awal untuk codelab pertama dalam seri.)
Dalam codelab ini, Anda akan meningkatkan aplikasi GuessTheWord dengan mengintegrasikan data binding dengan LiveData
dalam objek ViewModel
. Ini mengotomatiskan komunikasi antara tampilan dalam tata letak dan objek ViewModel
, dan memungkinkan Anda menyederhanakan kode dengan menggunakan LiveData
.
Layar judul |
Layar game |
Layar skor |
Dalam tugas ini, Anda akan menemukan dan menjalankan kode awal untuk codelab ini. Anda dapat menggunakan aplikasi GuessTheWord yang dibuat di codelab sebelumnya sebagai kode awal, atau Anda dapat mendownload aplikasi awal.
- (Opsional) Jika Anda tidak menggunakan kode dari codelab sebelumnya, download kode awal untuk codelab ini. Buka zip kode, lalu buka project di Android Studio.
- Jalankan aplikasi dan mainkan game.
- Perhatikan bahwa tombol Oke menampilkan kata berikutnya dan meningkatkan skor sebesar satu, sedangkan tombol Lewati menampilkan kata berikutnya dan menurunkan skor sebesar satu. Tombol Akhiri Game mengakhiri game.
- Lihat semua kata, dan perhatikan bahwa aplikasi otomatis membuka layar skor.
Dalam codelab sebelumnya, Anda menggunakan data binding sebagai jenis yang aman untuk mengakses tampilan di aplikasi GuessTheWord. Namun, kemampuan sebenarnya dari data binding adalah dalam melakukan hal yang disarankan namanya: mengikat data secara langsung ke objek tampilan di aplikasi Anda.
Arsitektur aplikasi saat ini
Di aplikasi Anda, tampilan ditentukan dalam tata letak XML, dan data untuk tampilan tersebut disimpan dalam objek ViewModel
. Di antara setiap tampilan dan ViewModel
yang sesuai adalah pengontrol UI, yang berfungsi sebagai relai di antara keduanya.
Misalnya:
- Tombol Got it didefinisikan sebagai tampilan
Button
dalam file tata letakgame_fragment.xml
. - Saat pengguna mengetuk tombol Got It, pemroses klik di fragmen
GameFragment
memanggil pemroses klik yang sesuai diGameViewModel
. - Skor diperbarui di
GameViewModel
.
Tampilan Button
dan GameViewModel
tidak berkomunikasi langsung—keduanya memerlukan pemroses klik yang berada di GameFragment
.
ViewModel yang diteruskan ke data binding
Akan lebih mudah jika tampilan dalam tata letak berkomunikasi langsung dengan data dalam objek ViewModel
, tanpa mengandalkan pengontrol UI sebagai perantara.
Objek ViewModel
menyimpan semua data UI di aplikasi GuessTheWord. Dengan meneruskan objek ViewModel
ke data binding, Anda dapat mengotomatiskan beberapa komunikasi antara tampilan dan objek ViewModel
.
Dalam tugas ini, Anda akan mengaitkan class GameViewModel
dan ScoreViewModel
dengan tata letak XML terkaitnya. Anda juga menyiapkan binding pemroses untuk menangani peristiwa klik.
Langkah 1: Tambahkan data binding untuk GameViewModel
Pada langkah ini, Anda akan mengaitkan GameViewModel
dengan file tata letak yang sesuai, game_fragment.xml
.
- Di file
game_fragment.xml
, tambahkan variabel data binding jenisGameViewModel
. Jika Anda mengalami error di Android Studio, bersihkan dan build ulang project.
<layout ...>
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
<androidx.constraintlayout...
- Di file
GameFragment
, teruskanGameViewModel
ke data binding.
Untuk melakukannya, tetapkanviewModel
ke variabelbinding.gameViewModel
, yang Anda deklarasikan di langkah sebelumnya. Masukkan kode ini di dalamonCreateView()
, setelahviewModel
diinisialisasi. Jika Anda mengalami error di Android Studio, bersihkan dan build ulang project.
// Set the viewmodel for databinding - this allows the bound layout access
// to all the data in the ViewModel
binding.gameViewModel = viewModel
Langkah 2: Gunakan binding pemroses untuk penanganan peristiwa
Binding pemroses adalah ekspresi binding yang berjalan saat peristiwa seperti onClick()
, onZoomIn()
, atau onZoomOut()
dipicu. Binding pemroses ditulis sebagai ekspresi lambda.
Data binding membuat pemroses dan menetapkan pemroses pada tampilan. Saat peristiwa yang didengarkan terjadi, pemroses akan mengevaluasi ekspresi lambda. Binding pemroses berfungsi dengan Plugin Android Gradle versi 2.0 atau lebih tinggi. Untuk mempelajari lebih lanjut, baca Tata letak dan ekspresi binding.
Pada langkah ini, Anda mengganti pemroses klik di GameFragment
dengan binding pemroses di file game_fragment.xml
.
- Di
game_fragment.xml
, tambahkan atributonClick
keskip_button
. Tentukan ekspresi binding dan panggil metodeonSkip()
diGameViewModel
. Ekspresi binding ini disebut binding pemroses.
<Button
android:id="@+id/skip_button"
...
android:onClick="@{() -> gameViewModel.onSkip()}"
... />
- Demikian pula, ikat peristiwa klik
correct_button
ke metodeonCorrect
()
diGameViewModel
.
<Button
android:id="@+id/correct_button"
...
android:onClick="@{() -> gameViewModel.onCorrect()}"
... />
- Ikat peristiwa klik
end_game_button
dengan metodeonGameFinish
()
diGameViewModel
.
<Button
android:id="@+id/end_game_button"
...
android:onClick="@{() -> gameViewModel.onGameFinish()}"
... />
- Di
GameFragment
, hapus pernyataan yang menetapkan pemroses klik, dan hapus fungsi yang dipanggil oleh pemroses klik. Anda tidak lagi memerlukannya.
Kode yang akan dihapus:
binding.correctButton.setOnClickListener { onCorrect() }
binding.skipButton.setOnClickListener { onSkip() }
binding.endGameButton.setOnClickListener { onEndGame() }
/** Methods for buttons presses **/
private fun onSkip() {
viewModel.onSkip()
}
private fun onCorrect() {
viewModel.onCorrect()
}
private fun onEndGame() {
gameFinished()
}
Langkah 3: Tambahkan data binding untuk ScoreViewModel
Pada langkah ini, Anda akan mengaitkan ScoreViewModel
dengan file tata letak yang sesuai, score_fragment.xml
.
- Di file
score_fragment.xml
, tambahkan variabel binding jenisScoreViewModel
. Langkah ini mirip dengan langkah yang Anda lakukan untukGameViewModel
di atas.
<layout ...>
<data>
<variable
name="scoreViewModel"
type="com.example.android.guesstheword.screens.score.ScoreViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
- Di
score_fragment.xml
, tambahkan atributonClick
keplay_again_button
. Tentukan binding pemroses dan panggil metodeonPlayAgain()
diScoreViewModel
.
<Button
android:id="@+id/play_again_button"
...
android:onClick="@{() -> scoreViewModel.onPlayAgain()}"
... />
- Di
ScoreFragment
, di dalamonCreateView()
, lakukan inisialisasiviewModel
. Lalu lakukan inisialisasi variabel bindingbinding.scoreViewModel
.
viewModel = ...
binding.scoreViewModel = viewModel
- Di
ScoreFragment
, hapus kode yang menetapkan pemroses klik untukplayAgainButton
. Jika Android Studio menampilkan error, bersihkan dan lakukan build ulang pada project.
Kode yang akan dihapus:
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
- Jalankan aplikasi Anda. Aplikasi seharusnya berfungsi seperti sebelumnya, tetapi sekarang tampilan tombol berkomunikasi langsung dengan objek
ViewModel
. Tampilan tidak lagi berkomunikasi melalui pengendali klik tombol diScoreFragment
.
Memecahkan masalah pesan error data binding
Jika aplikasi menggunakan data binding, proses kompilasi akan menghasilkan class perantara yang digunakan untuk data binding. Aplikasi dapat berisi error yang tidak terdeteksi oleh Android Studio hingga Anda mencoba mengompilasi aplikasi, sehingga Anda tidak melihat peringatan atau kode merah saat menulis kode. Namun pada waktu kompilasi, Anda akan mendapatkan error samar yang berasal dari class perantara yang dihasilkan.
Jika Anda mendapatkan pesan error samar:
- Perhatikan dengan cermat pesan di panel Build Android Studio. Jika Anda melihat lokasi yang berakhiran
databinding
, berarti terjadi error dengan data binding. - Pada file XML tata letak, periksa error pada atribut
onClick
yang menggunakan data binding. Cari fungsi yang dipanggil ekspresi lambda, dan pastikan ekspresi tersebut ada. - Di bagian
<data>
pada XML, periksa ejaan variabel data binding.
Misalnya, perhatikan kesalahan ejaan nama fungsi onCorrect()
dalam nilai atribut berikut:
android:onClick="@{() -> gameViewModel.onCorrectx()}"
Perhatikan juga kesalahan ejaan gameViewModel
di bagian <data>
file XML:
<data>
<variable
name="gameViewModelx"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
Android Studio tidak mendeteksi error seperti ini hingga Anda mengompilasi aplikasi, lalu compiler menampilkan pesan error seperti berikut:
error: cannot find symbol import com.example.android.guesstheword.databinding.GameFragmentBindingImpl" symbol: class GameFragmentBindingImpl location: package com.example.android.guesstheword.databinding
Data binding berfungsi baik dengan LiveData
yang digunakan dengan objek ViewModel
. Setelah menambahkan data binding ke objek ViewModel
, Anda siap menggabungkan LiveData
.
Dalam tugas ini, Anda mengubah aplikasi GuessTheWord untuk menggunakan LiveData
sebagai sumber data binding untuk memberi tahu UI tentang perubahan data, tanpa menggunakan metode observer LiveData
.
Langkah 1: Tambahkan kata LiveData ke file game_fragment.xml
Pada langkah ini, Anda mengikat tampilan teks kata saat ini langsung ke objek LiveData
di ViewModel
.
- Di
game_fragment.xml
, tambahkan atributandroid:text
ke tampilan teksword_text
.
Tetapkan variabel tersebut ke objek LiveData
, word
dari GameViewModel
, menggunakan variabel binding, gameViewModel
.
<TextView
android:id="@+id/word_text"
...
android:text="@{gameViewModel.word}"
... />
Perhatikan bahwa Anda tidak perlu menggunakan word.value
. Sebagai gantinya, Anda dapat menggunakan objek LiveData
sebenarnya. Objek LiveData
menampilkan nilai word
saat ini. Jika nilai word
null, objek LiveData
akan menampilkan string kosong.
- Di
GameFragment
, dionCreateView()
, setelah menginisialisasigameViewModel
, tetapkan aktivitas saat ini sebagai pemilik siklus proses variabelbinding
. Ini menentukan cakupan objekLiveData
di atas, yang memungkinkan objek untuk otomatis memperbarui tampilan dalam tata letak,game_fragment.xml
.
binding.gameViewModel = ...
// Specify the current activity as the lifecycle owner of the binding.
// This is used so that the binding can observe LiveData updates
binding.lifecycleOwner = this
- Di
GameFragment
, hapus observer untukLiveData
word
.
Kode yang akan dihapus:
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
binding.wordText.text = newWord
})
- Jalankan aplikasi dan mainkan game. Sekarang kata saat ini sedang diperbarui tanpa metode pengamat di pengontrol UI.
Langkah 2: Tambahkan skor LiveData ke file score_fragment.xml
Pada langkah ini, Anda mengikat LiveData
score
ke tampilan teks skor di fragmen skor.
- Di
score_fragment.xml
, tambahkan atributandroid:text
ke tampilan teks skor. TetapkanscoreViewModel.score
ke atributtext
. Karenascore
adalah bilangan bulat, konversikan menjadi string menggunakanString.valueOf()
.
<TextView
android:id="@+id/score_text"
...
android:text="@{String.valueOf(scoreViewModel.score)}"
... />
- Di
ScoreFragment
, setelah menginisialisasiscoreViewModel
, tetapkan aktivitas saat ini sebagai pemilik siklus proses variabelbinding
.
binding.scoreViewModel = ...
// Specify the current activity as the lifecycle owner of the binding.
// This is used so that the binding can observe LiveData updates
binding.lifecycleOwner = this
- Di
ScoreFragment
, hapus observer untuk objekscore
.
Kode yang akan dihapus:
// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
- Jalankan aplikasi dan mainkan game. Perhatikan bahwa skor di fragmen skor ditampilkan dengan benar, tanpa pengamat di fragmen skor.
Langkah 3: Tambahkan pemformatan string dengan data binding
Di tata letak, Anda dapat menambahkan pemformatan string bersama dengan data binding. Dalam tugas ini, Anda memformat kata saat ini untuk menambahkan tanda kutip di sekitarnya. Anda juga dapat memformat string skor sebagai awalan Skor Saat Ini, seperti yang ditunjukkan pada gambar berikut.
- Di
string.xml
, tambahkan string berikut, yang akan Anda gunakan untuk memformat tampilan teksword
danscore
.%s
dan%d
adalah placeholder untuk kata dan skor saat ini.
<string name="quote_format">\"%s\"</string>
<string name="score_format">Current Score: %d</string>
- Di
game_fragment.xml
, perbarui atributtext
dari tampilan teksword_text
untuk menggunakan resource stringquote_format
. LewatigameViewModel.word
. Ini meneruskan kata saat ini sebagai argumen ke string pemformatan.
<TextView
android:id="@+id/word_text"
...
android:text="@{@string/quote_format(gameViewModel.word)}"
... />
- Format tampilan teks
score
yang mirip denganword_text
. Digame_fragment.xml
, tambahkan atributtext
ke tampilan teksscore_text
. Gunakan resource stringscore_format
, yang menggunakan satu argumen numerik, yang diwakili oleh placeholder%d
. Teruskan objekLiveData
,score
, sebagai argumen ke string pemformatan ini.
<TextView
android:id="@+id/score_text"
...
android:text="@{@string/score_format(gameViewModel.score)}"
... />
- Di class
GameFragment
, di dalam metodeonCreateView()
, hapus kode observerscore
.
Kode yang akan dihapus:
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
- Bersihkan, build ulang, dan jalankan aplikasi Anda, lalu mainkan game. Perhatikan bahwa kata saat ini dan skor diformat di layar game.
Selamat! Anda telah mengintegrasikan LiveData
dan ViewModel
dengan data binding di aplikasi Anda. Ini memungkinkan tampilan pada tata letak berkomunikasi langsung dengan ViewModel
, tanpa menggunakan pengendali klik dalam fragmen. Anda juga telah menggunakan objek LiveData
sebagai sumber data binding untuk otomatis memberi tahu UI tentang perubahan data, tanpa metode observer LiveData
.
Project Android Studio: GuessTheWord
- Library Data Binding berfungsi sempurna dengan Komponen Arsitektur Android seperti
ViewModel
danLiveData
. - Tata letak di aplikasi Anda dapat diikat ke data di Komponen Arsitektur, yang sudah membantu Anda mengelola siklus proses pengontrol UI dan memberi tahu tentang perubahan dalam data.
Data binding ViewModel
- Anda dapat mengaitkan
ViewModel
dengan tata letak menggunakan data binding. - Objek
ViewModel
menyimpan data UI. Dengan meneruskan objekViewModel
ke data binding, Anda dapat mengotomatiskan beberapa komunikasi antara tampilan dan objekViewModel
.
Cara mengaitkan ViewModel
dengan tata letak:
- Di file tata letak, tambahkan variabel data binding jenis
ViewModel
.
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
- Di file
GameFragment
, teruskanGameViewModel
ke data binding.
binding.gameViewModel = viewModel
Binding pemroses
- Binding pemroses adalah ekspresi binding di tata letak yang berjalan saat peristiwa klik seperti
onClick()
dipicu. - Binding pemroses ditulis sebagai ekspresi lambda.
- Dengan menggunakan binding pemroses, Anda mengganti pemroses klik di pengontrol UI dengan binding pemroses di file tata letak.
- Data binding membuat pemroses dan menetapkan pemroses pada tampilan.
android:onClick="@{() -> gameViewModel.onSkip()}"
Menambahkan LiveData ke data binding
- Objek
LiveData
dapat digunakan sebagai sumber data binding untuk otomatis memberi tahu UI tentang perubahan data. - Anda dapat mengikat tampilan langsung ke objek
LiveData
diViewModel
. JikaLiveData
diViewModel
berubah, tampilan di tata letak dapat diupdate secara otomatis, tanpa metode pengamat di pengontrol UI.
android:text="@{gameViewModel.word}"
- Agar data binding
LiveData
berfungsi, tetapkan aktivitas saat ini (pengontrol UI) sebagai pemilik siklus proses variabelbinding
di pengontrol UI.
binding.lifecycleOwner = this
Pemformatan string dengan data binding
- Dengan menggunakan data binding, Anda dapat memformat resource string dengan placeholder seperti
%s
untuk string dan%d
untuk bilangan bulat. - Untuk memperbarui atribut
text
tampilan, teruskan objekLiveData
sebagai argumen ke string pemformatan.
android:text="@{@string/quote_format(gameViewModel.word)}"
Kursus Udacity:
Dokumentasi developer Android:
Bagian ini mencantumkan kemungkinan tugas pekerjaan rumah untuk siswa yang mengerjakan codelab ini sebagai bagian dari kursus yang dipimpin oleh instruktur. Terserah instruktur untuk melakukan hal berikut:
- Tugaskan pekerjaan rumah jika diperlukan.
- Berkomunikasi dengan siswa cara mengirimkan tugas pekerjaan rumah.
- Beri nilai tugas pekerjaan rumah.
Instruktur dapat menggunakan saran ini sesedikit atau sebanyak yang mereka inginkan, dan harus bebas memberikan pekerjaan rumah lain yang dirasa sesuai.
Jika Anda mengerjakan codelab ini sendiri, silakan gunakan tugas pekerjaan rumah ini untuk menguji pengetahuan Anda.
Jawab pertanyaan berikut
Pertanyaan 1
Manakah dari pernyataan berikut yang tidak benar tentang binding pemroses?
- Binding pemroses adalah ekspresi binding yang berjalan saat peristiwa terjadi.
- Binding pemroses berfungsi dengan semua versi plugin Android Gradle.
- Binding pemroses ditulis sebagai ekspresi lambda.
- Binding pemroses mirip dengan referensi metode, tetapi memungkinkan Anda menjalankan ekspresi data binding arbitrer.
Pertanyaan 2
Anggap aplikasi Anda menyertakan resource string ini:<string name="generic_name">Hello %s</string>
Manakah dari hal berikut merupakan sintaksis yang benar untuk pemformatan string, menggunakan ekspresi data binding?
android:text= "@{@string/generic_name(user.name)}"
android:text= "@{string/generic_name(user.name)}"
android:text= "@{@generic_name(user.name)}"
android:text= "@{@string/generic_name,user.name}"
Pertanyaan 3
Kapan ekspresi binding pemroses dievaluasi dan dijalankan?
- Saat data yang disimpan oleh
LiveData
diubah - Saat aktivitas dibuat ulang karena perubahan konfigurasi
- Saat peristiwa seperti
onClick()
terjadi - Saat aktivitas berpindah ke latar belakang
Mulai tutorial berikutnya:
Untuk link ke codelab lainnya dalam kursus ini, lihat halaman landing codelab Dasar-Dasar Kotlin Android.