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
Aplikasi GuessTheWord yang Anda kerjakan di tiga codelab sebelumnya mengimplementasikan pola observer LiveData
untuk mengamati data ViewModel
. Tampilan di pengontrol UI mengamati LiveData
di ViewModel
dan memperbarui data yang akan ditampilkan.
Saat meneruskan LiveData
antar-komponen, terkadang Anda mungkin ingin memetakan atau mengubah data. Kode Anda mungkin perlu melakukan penghitungan, hanya menampilkan subkumpulan data, atau mengubah rendisi data. Misalnya, untuk word
LiveData
, Anda dapat membuat transformasi yang menampilkan jumlah huruf dalam kata, bukan kata itu sendiri.
Anda dapat mentransformasi LiveData
menggunakan metode bantuan di class Transformations
:
Dalam codelab ini, Anda menambahkan penghitung mundur di aplikasi. Anda akan mempelajari cara menggunakan Transformations.map()
di LiveData
untuk mengubah waktu yang sudah berlalu menjadi format untuk ditampilkan di layar.
Yang harus sudah Anda ketahui
- Cara membuat aplikasi Android dasar di Kotlin
- Cara menggunakan objek
ViewModel
di aplikasi Anda - Cara menyimpan data menggunakan
LiveData
diViewModel
- Cara menambahkan metode observer
LiveData
untuk mengamati perubahan dalam data - Cara menggunakan data binding dengan
ViewModel
danLiveData
Yang akan Anda pelajari
- Cara menggunakan
Transformations
denganLiveData
Yang akan Anda lakukan
- Tambahkan timer untuk mengakhiri game.
- Gunakan
Transformations.map()
untuk mengubah satuLiveData
menjadi yang lain.
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 menambahkan penghitung mundur satu menit yang muncul di atas skor. Timer mengakhiri game saat hitung mundur mencapai 0
.
Anda juga menggunakan transformasi untuk memformat objek LiveData
yang berlalu menjadi objek LiveData
string timer. LiveData
yang ditransformasi adalah sumber data binding untuk tampilan teks timer.
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 Skip menampilkan kata berikutnya dan menurunkan skor sebesar satu, dan tombol Got it menunjukkan kata berikutnya dan meningkatkan skor sebesar satu. Tombol Akhiri Game mengakhiri game.
- Lihat semua kata, dan perhatikan bahwa aplikasi otomatis membuka layar skor.
Dalam tugas ini, Anda menambahkan penghitung mundur ke aplikasi. Alih-alih game berakhir saat daftar kata kosong, game berakhir saat timer selesai. Android menyediakan class utilitas yang disebut CountDownTimer
yang Anda gunakan untuk menerapkan timer.
Tambahkan logika untuk timer di GameViewModel
sehingga timer tidak dihancurkan selama perubahan konfigurasi. Fragmen berisi kode untuk memperbarui tampilan teks timer saat timer berjalan.
Terapkan langkah-langkah berikut di class GameViewModel
:
- Buat objek
companion
untuk menyimpan konstanta timer.
companion object {
// Time when the game is over
private const val DONE = 0L
// Countdown time interval
private const val ONE_SECOND = 1000L
// Total time for the game
private const val COUNTDOWN_TIME = 60000L
}
- Untuk menyimpan waktu hitung mundur timer, tambahkan variabel anggota
MutableLiveData
yang disebut_currentTime
dan properti pendukung,currentTime
.
// Countdown time
private val _currentTime = MutableLiveData<Long>()
val currentTime: LiveData<Long>
get() = _currentTime
- Tambahkan variabel anggota
private
yang disebuttimer
dari jenisCountDownTimer
. Anda mengatasi error inisialisasi pada langkah berikutnya.
private val timer: CountDownTimer
- Di dalam blok
init
, lakukan inisialisasi dan mulai timer. Teruskan total waktu,COUNTDOWN_TIME
. Untuk interval waktu, gunakanONE_SECOND
. Ganti metode callbackonTick()
danonFinish()
lalu mulai timer.
// Creates a timer which triggers the end of the game when it finishes
timer = object : CountDownTimer(COUNTDOWN_TIME, ONE_SECOND) {
override fun onTick(millisUntilFinished: Long) {
}
override fun onFinish() {
}
}
timer.start()
- Implementasikan metode callback
onTick()
, yang dipanggil pada setiap interval atau pada setiap centang. Perbarui_currentTime
, menggunakan parameter yang diteruskanmillisUntilFinished
.millisUntilFinished
adalah jumlah waktu hingga timer selesai dalam milidetik. KonversikanmillisUntilFinished
ke detik dan tetapkan ke_currentTime
.
override fun onTick(millisUntilFinished: Long)
{
_currentTime.value = millisUntilFinished/ONE_SECOND
}
- Metode callback
onFinish()
dipanggil saat timer selesai. ImplementasikanonFinish()
untuk mengupdate_currentTime
dan memicu peristiwa penyelesaian game.
override fun onFinish() {
_currentTime.value = DONE
onGameFinish()
}
- Perbarui metode
nextWord()
untuk mereset daftar kata saat daftar kosong, bukan menyelesaikan game.
private fun nextWord() {
// Shuffle the word list, if the list is empty
if (wordList.isEmpty()) {
resetList()
} else {
// Remove a word from the list
_word.value = wordList.removeAt(0)
}
- Di dalam metode
onCleared()
, batalkan timer untuk menghindari kebocoran memori. Anda dapat menghapus laporan log, karena laporan tersebut tidak diperlukan lagi. MetodeonCleared()
dipanggil sebelumViewModel
dihancurkan.
override fun onCleared() {
super.onCleared()
// Cancel the timer
timer.cancel()
}
- Jalankan aplikasi dan mainkan game. Tunggu selama 60 detik, dan game akan selesai secara otomatis. Namun, teks timer tidak ditampilkan di layar. Anda akan memperbaikinya nanti.
Metode Transformations.map()
memberikan cara untuk melakukan manipulasi data pada LiveData
sumber dan menampilkan objek LiveData
hasil. Transformasi ini tidak dihitung kecuali jika pengamat mengamati objek LiveData
yang ditampilkan.
Metode ini menggunakan LiveData
sumber dan suatu fungsi sebagai parameter. Fungsi ini memanipulasi LiveData
sumber.
Dalam tugas ini, Anda memformat objek LiveData
waktu yang berlalu ke objek LiveData
string baru dalam format "MM:SS
" Anda juga menampilkan waktu berlalu yang diformat di layar.
File tata letak game_fragment.xml
sudah menyertakan tampilan teks timer. Sejauh ini, tampilan teks tidak memiliki teks untuk ditampilkan, sehingga teks timer belum terlihat.
- Di class
GameViewModel
, setelah membuat instancecurrentTime
, buat objekLiveData
baru bernamacurrentTimeString
. Objek ini ditujukan untuk versi string berformatcurrentTime
. - Gunakan
Transformations.map()
untuk menentukancurrentTimeString
. TeruskancurrentTime
dan fungsi lambda untuk memformat waktu. Anda dapat menerapkan fungsi lambda menggunakan metode utilitasDateUtils.formatElapsedTime()
, yang mengambillong
jumlah milidetik dan memformatnya ke "MM:SS
" format string.
// The String version of the current time
val currentTimeString = Transformations.map(currentTime) { time ->
DateUtils.formatElapsedTime(time)
}
- Pada file
game_fragment.xml
, di tampilan teks timer, ikat atributtext
kecurrentTimeString
darigameViewModel
.
<TextView
android:id="@+id/timer_text"
...
android:text="@{gameViewModel.currentTimeString}"
... />
- Jalankan aplikasi dan mainkan game. Teks timer diperbarui satu detik sekali. Perhatikan bahwa game tidak selesai jika Anda telah melihat semua kata secara bergantian. Game sekarang selesai saat timer habis.
Selamat! Anda berhasil menambahkan timer ke aplikasi yang otomatis mengakhiri game. Anda juga telah mempelajari cara menggunakan Transformations.map()
untuk mengonversi satu objek LiveData
ke objek lainnya.
Project Android Studio: GuessTheWord
Tantangan: Buat petunjuk tentang kata, dan tampilkan petunjuk dalam tampilan teks di atas timer. Petunjuk ini dapat memberitahukan jumlah karakter yang dimiliki kata, dan dapat menampilkan salah satu huruf pada posisi acak.
Petunjuk: Gunakan Transformations.map()
pada objek word
LiveData
saat ini. Menambahkan TextView
tambahan untuk menampilkan petunjuk kata.
- Di class
GameViewModel
, tambahkanval
untuk mengubah kata saat ini menjadi petunjuk.
// The Hint for the current word
val wordHint = Transformations.map(word) { word ->
val randomPosition = (1..word.length).random()
"Current word has " + word.length + " letters" +
"\nThe letter at position " + randomPosition + " is " +
word.get(randomPosition - 1).toUpperCase()
}
- Di
game_fragment.xml
, tambahkan tampilan teks baru di atas tampilan teks timer untuk menampilkan petunjuk. Ikat atribut teks denganwordHint
yang Anda tambahkan di atas.
android:text="@{gameViewModel.wordHint}"
Mentransformasi LiveData
- Terkadang Anda ingin mengubah hasil
LiveData
. Misalnya, Anda dapat memformat stringDate
sebagai "hours:mins:seconds," atau menampilkan jumlah item dalam daftar, bukan menampilkan daftar itu sendiri. Untuk melakukan transformasi padaLiveData
, gunakan metode bantuan di classTransformations
. - Metode
Transformations.map()
memberikan cara mudah untuk melakukan manipulasi data padaLiveData
dan menampilkan objekLiveData
lainnya. Praktik yang direkomendasikan adalah menempatkan logika pemformatan data yang menggunakan classTransformations
diViewModel
bersama dengan data UI.
Menampilkan hasil transformasi di TextView
- Pastikan data sumber ditentukan sebagai
LiveData
diViewModel
. - Tentukan variabel, misalnya
newResult
. GunakanTransformation.map()
untuk melakukan transformasi dan menampilkan hasilnya ke variabel.
val newResult = Transformations.map(someLiveData) { input ->
// Do some transformation on the input live data
// and return the new value
}
- Pastikan file tata letak yang berisi
TextView
mendeklarasikan variabel<data>
untukViewModel
.
<data> <variable name="MyViewModel" type="com.example.android.something.MyViewModel" /> </data>
- Di file tata letak, tetapkan atribut
text
dariTextView
ke bindingnewResult
dariViewModel
. Contoh:
android:text="@{SomeViewModel.newResult}"
Memformat tanggal
- Metode utilitas
DateUtils.formatElapsedTime()
membutuhkan jumlahlong
milidetik dan memformat nomor untuk menggunakan format stringMM:SS
.
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
Di class mana Anda harus menambahkan logika pemformatan data yang menggunakan metode Transformations.map()
untuk mengonversi LiveData
ke nilai atau format yang berbeda?
ViewModel
Fragment
Activity
MainActivity
Pertanyaan 2
Metode Transformations.map()
memberikan cara mudah untuk melakukan manipulasi data pada LiveData
dan menampilkan __________ .
- Objek
ViewModel
- Objek
LiveData
String
berformat- Objek
RoomDatabase
Pertanyaan 3
Apa saja parameter untuk metode Transformations.map()
?
LiveData
sumber dan fungsi yang akan diterapkan keLiveData
- Hanya sumber
LiveData
- Tidak ada parameter
ViewModel
dan fungsi yang akan diterapkan
Pertanyaan 4
Fungsi lambda yang diteruskan ke metode Transformations.map()
dijalankan di thread mana?
- Thread utama
- Thread latar belakang
- UI thread
- Di coroutine
Mulai pelajaran berikutnya:
Untuk link ke codelab lainnya dalam kursus ini, lihat halaman landing codelab Dasar-Dasar Kotlin Android.