Codelab นี้เป็นส่วนหนึ่งของหลักสูตรพื้นฐานเกี่ยวกับ Kotlin ใน Android คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้ หากทํางานผ่าน Codelab ตามลําดับ Codelab ของหลักสูตรทั้งหมดจะแสดงอยู่ในหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals
บทนำ
ใน Codelab ก่อนหน้าในบทเรียนนี้ คุณได้ปรับปรุงโค้ดของแอป GuessTheWord แล้ว ตอนนี้แอปใช้ออบเจ็กต์ ViewModel
ดังนั้นข้อมูลแอปจึงมีผลต่อการเปลี่ยนแปลงการกําหนดค่าอุปกรณ์ เช่น การหมุนหน้าจอและการเปลี่ยนแปลงของความพร้อมใช้งานของแป้นพิมพ์ คุณเพิ่ม LiveData
ที่สังเกตได้ด้วย เพื่อให้การแจ้งเตือนได้รับการแจ้งเตือนโดยอัตโนมัติเมื่อข้อมูลที่มีการเปลี่ยนแปลงมีการเปลี่ยนแปลง
ใน Codelab นี้ คุณจะทํางานกับแอป GuessTheWord ต่อไป คุณจะเชื่อมโยงมุมมองกับคลาส ViewModel
ในแอปเพื่อให้มุมมองในเลย์เอาต์สื่อสารกับออบเจ็กต์ ViewModel
ได้โดยตรง (ที่ผ่านมาจนถึงตอนนี้แอป ข้อมูลพร็อพเพอร์ตี้ได้สื่อสารกับทางอ้อมกับ ViewModel
ตามส่วนย่อยของแอป) หลังจากผสานรวมการเชื่อมโยงข้อมูลกับออบเจ็กต์ ViewModel
แล้ว คุณไม่จําเป็นต้องใช้เครื่องจัดการการคลิกใน Fragment ของแอปอีกต่อไป คุณจึงนําออกได้
นอกจากนี้คุณยังเปลี่ยนแอป GuessTheWord เพื่อใช้ LiveData
เป็นแหล่งข้อมูลแบบผูกข้อมูลเพื่อแจ้ง UI เกี่ยวกับการเปลี่ยนแปลงในข้อมูลโดยไม่ต้องใช้เมธอดการสังเกตการณ์ LiveData
รายการ
สิ่งที่ควรทราบอยู่แล้ว
- วิธีสร้างแอป Android ขั้นพื้นฐานใน Kotlin
- วิธีการทํางานของวงจรกิจกรรมและส่วนย่อย
- วิธีใช้ออบเจ็กต์
ViewModel
ในแอป - วิธีเก็บข้อมูลโดยใช้
LiveData
ในViewModel
- วิธีเพิ่มวิธีการสังเกตการณ์เพื่อดูการเปลี่ยนแปลงในข้อมูล
LiveData
สิ่งที่คุณจะได้เรียนรู้
- วิธีใช้องค์ประกอบของไลบรารีการเชื่อมโยงข้อมูล
- วิธีผสานรวม
ViewModel
กับการเชื่อมโยงข้อมูล - วิธีผสานรวม
LiveData
กับการเชื่อมโยงข้อมูล - วิธีใช้การเชื่อมโยง Listener เพื่อแทนที่ Listener การคลิกในส่วนย่อย
- วิธีเพิ่มการจัดรูปแบบสตริงในนิพจน์การเชื่อมโยงข้อมูล
สิ่งที่คุณจะทํา
- มุมมองในเลย์เอาต์ GuessTheWord จะสื่อสารกับออบเจ็กต์
ViewModel
ทางอ้อมโดยใช้ตัวควบคุม UI (ส่วนย่อย) เพื่อส่งต่อข้อมูล ใน Codelab นี้ คุณสามารถเชื่อมโยงมุมมองของแอปกับออบเจ็กต์ViewModel
เพื่อให้มุมมองสื่อสารกับออบเจ็กต์ViewModel
โดยตรง - คุณเปลี่ยนแอปให้ใช้
LiveData
เป็นแหล่งที่มาของการเชื่อมโยงข้อมูล หลังจากการเปลี่ยนแปลงนี้ ออบเจ็กต์LiveData
จะแจ้ง UI เกี่ยวกับการเปลี่ยนแปลงในข้อมูล และไม่จําเป็นต้องใช้เมธอดการสังเกตการณ์LiveData
อีกต่อไป
ใน Codelab บทที่ 5 คุณจะพัฒนาแอป GuessTheWord ได้โดยเริ่มต้นด้วยโค้ดเริ่มต้น GuessTheWord เป็นเกมสไตล์ชาร์ดแบบผู้เล่น 2 คน ซึ่งผู้เล่นจะทํางานร่วมกันเพื่อให้ได้คะแนนสูงสุดเท่าที่จะเป็นไปได้
ผู้เล่นคนแรกจะดูคําในแอปและกระทําทีละคํา และอย่าแสดงคํานั้นให้ผู้เล่นคนที่สองเห็น ผู้เล่นรายที่ 2 พยายามเดาคํานั้น
ในการเล่นเกม ผู้เล่นคนแรกจะเปิดแอปในอุปกรณ์และจะเห็นคํา เช่น "guitar," ดังที่แสดงในภาพหน้าจอด้านล่าง
ผู้เล่นคนแรกจะทําตามคําและระวังอย่าพูดคํานั้นจริงๆ
- เมื่อผู้เล่นคนที่ 2 เดาคําได้อย่างถูกต้อง ผู้เล่นคนแรกจะกดปุ่มรับทราบ ซึ่งจะเพิ่มจํานวนเป็น 1 และแสดงคําถัดไป
- หากผู้เล่นรายที่ 2 เดาคําไม่ได้ ผู้เล่นคนแรกจะกดปุ่มข้าม ซึ่งจะลดจํานวนลงและข้ามไปยังคําถัดไป
- หากต้องการจบเกม ให้กดปุ่มจบเกม (ฟังก์ชันนี้จะไม่อยู่ในโค้ดเริ่มต้นสําหรับ Codelab แรกในชุด)
ใน Codelab นี้ คุณสามารถปรับปรุงแอป GuessTheWord ได้โดยการผสานรวมการเชื่อมโยงข้อมูลกับ LiveData
ในออบเจ็กต์ ViewModel
วิธีนี้จะช่วยให้การสื่อสารระหว่างมุมมองในเลย์เอาต์และออบเจ็กต์ ViewModel
เป็นไปโดยอัตโนมัติ และให้คุณทําให้โค้ดง่ายขึ้นโดยใช้ LiveData
หน้าจอชื่อ | หน้าจอเกม | หน้าจอคะแนน |
ในงานนี้ คุณจะค้นหาและเรียกใช้โค้ดเริ่มต้นสําหรับ Codelab นี้ คุณจะใช้แอป GuessTheWord ที่สร้างไว้ใน Codelab ก่อนหน้าเป็นโค้ดเริ่มต้น หรือจะดาวน์โหลดแอปเริ่มต้นก็ได้
- (ไม่บังคับ) หากคุณไม่ได้ใช้โค้ดจาก Codelab ก่อนหน้า ให้ดาวน์โหลดโค้ดเริ่มต้นสําหรับ Codelab นี้ แตกไฟล์โค้ดแล้วเปิดโปรเจ็กต์ใน Android Studio
- เรียกใช้แอปและเล่นเกม
- โปรดสังเกตว่าปุ่มรับทราบจะแสดงคําถัดไปและเพิ่มคะแนนเป็น 1 รายการ ขณะที่ปุ่มข้ามแสดงคําถัดไปและลดคะแนนลง 1 รายการ ปุ่มสิ้นสุดเกมจะจบเกม
- เลื่อนดูคําทั้งหมด แล้วสังเกตว่าแอปไปยังหน้าจอคะแนนโดยอัตโนมัติ
ใน Codelab ที่ผ่านมา คุณได้ใช้การเชื่อมโยงข้อมูลเป็นวิธีที่ปลอดภัยในการเข้าถึงข้อมูลพร็อพเพอร์ตี้ในแอป GuessTheWord แต่ความสามารถที่แท้จริงของการเชื่อมโยงข้อมูลคือการดําเนินการตามชื่อ ซึ่งก็คือการเชื่อมโยงข้อมูลโดยตรงกับออบเจ็กต์ข้อมูลพร็อพเพอร์ตี้ในแอป
สถาปัตยกรรมแอปปัจจุบัน
ในแอป ระบบจะกําหนดข้อมูลพร็อพเพอร์ตี้ในเลย์เอาต์ XML และข้อมูลของข้อมูลพร็อพเพอร์ตี้เหล่านั้นจะอยู่ในออบเจ็กต์ ViewModel
ระหว่างข้อมูลพร็อพเพอร์ตี้แต่ละรายการกับ ViewModel
ที่เกี่ยวข้อง เป็นตัวควบคุม UI ซึ่งทําหน้าที่ส่งต่อข้อมูลระหว่างแต่ละรายการ
เช่น
- ปุ่มรับทราบหมายถึงมุมมอง
Button
ในไฟล์เลย์เอาต์game_fragment.xml
- เมื่อผู้ใช้แตะปุ่มรับทราบ Listener การคลิกในส่วน
GameFragment
จะเรียก Listener การคลิกที่เกี่ยวข้องในGameViewModel
- คะแนนจะอัปเดตใน
GameViewModel
มุมมอง Button
และ GameViewModel
ไม่ได้สื่อสารกันโดยตรง เพราะคุณต้องใช้ Listener การคลิกใน GameFragment
Viewmodel ที่ส่งผ่านการเชื่อมโยงข้อมูลแล้ว
ทําได้ง่ายขึ้นหากมุมมองในเลย์เอาต์สื่อสารกับข้อมูลโดยตรงในออบเจ็กต์ ViewModel
โดยไม่ต้องอาศัยตัวควบคุม UI เป็นตัวกลาง
ออบเจ็กต์ ViewModel
จะเก็บข้อมูล UI ทั้งหมดในแอป GuessTheWord เมื่อส่งออบเจ็กต์ ViewModel
ไปยังการเชื่อมโยงข้อมูล คุณจะทําให้การสื่อสารบางอย่างระหว่างข้อมูลพร็อพเพอร์ตี้และออบเจ็กต์ ViewModel
เป็นแบบอัตโนมัติได้
ในงานนี้ คุณจะได้เชื่อมโยงชั้นเรียน GameViewModel
และ ScoreViewModel
กับเลย์เอาต์ XML ที่เกี่ยวข้อง รวมถึงตั้งค่าการเชื่อมโยง Listener เพื่อจัดการเหตุการณ์การคลิกด้วย
ขั้นตอนที่ 1: เพิ่มการเชื่อมโยงข้อมูลสําหรับ GameViewmodel
ในขั้นตอนนี้ คุณจะเชื่อมโยง GameViewModel
กับไฟล์เลย์เอาต์ที่เกี่ยวข้อง game_fragment.xml
- ในไฟล์
game_fragment.xml
ให้เพิ่มตัวแปรการเชื่อมโยงของประเภทGameViewModel
หากมีข้อผิดพลาดใน Android Studio ให้ทําความสะอาดและสร้างโปรเจ็กต์ใหม่
<layout ...>
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
<androidx.constraintlayout...
- ในไฟล์
GameFragment
ให้ส่งGameViewModel
ไปยังการเชื่อมโยงข้อมูล
โดยกําหนดviewModel
ให้กับตัวแปรbinding.gameViewModel
ที่คุณประกาศในขั้นตอนก่อนหน้า วางโค้ดนี้ไว้ภายในonCreateView()
หลังจากเริ่มใช้viewModel
หากมีข้อผิดพลาดใน Android Studio ให้ทําความสะอาดและสร้างโปรเจ็กต์ใหม่
// Set the viewmodel for databinding - this allows the bound layout access
// to all the data in the ViewModel
binding.gameViewModel = viewModel
ขั้นตอนที่ 2: ใช้การเชื่อมโยง Listener สําหรับการจัดการเหตุการณ์
การเชื่อมโยง Listener คือนิพจน์การเชื่อมโยงที่จะทํางานเมื่อมีการทริกเกอร์เหตุการณ์ เช่น onClick()
, onZoomIn()
หรือ onZoomOut()
การเชื่อมโยง Listener จะถูกเขียนเป็นนิพจน์แลมบ์ดา
การเชื่อมโยงข้อมูลจะสร้าง Listener และตั้งค่า Listener ในข้อมูลพร็อพเพอร์ตี้ เมื่อมีเหตุการณ์ Listener สําหรับ Listener จะประเมินนิพจน์แลมบ์ดา Listener การเชื่อมโยงใช้งานได้กับปลั๊กอิน Android Gradle เวอร์ชัน 2.0 ขึ้นไป หากต้องการดูข้อมูลเพิ่มเติม โปรดอ่านเลย์เอาต์และนิพจน์การเชื่อมโยง
ในขั้นตอนนี้ คุณจะแทนที่ Listener การคลิกในGameFragment
ด้วยการเชื่อมโยง Listener ในไฟล์ game_fragment.xml
- ใน
game_fragment.xml
ให้เพิ่มแอตทริบิวต์onClick
ลงในskip_button
กําหนดนิพจน์การเชื่อมโยงและเรียกเมธอดonSkip()
ในGameViewModel
นิพจน์การเชื่อมโยงนี้เรียกว่าการเชื่อมโยงผู้ฟัง
<Button
android:id="@+id/skip_button"
...
android:onClick="@{() -> gameViewModel.onSkip()}"
... />
- ในทํานองเดียวกัน ให้เชื่อมโยงเหตุการณ์การคลิก
correct_button
กับเมธอดonCorrect
()
ในGameViewModel
<Button
android:id="@+id/correct_button"
...
android:onClick="@{() -> gameViewModel.onCorrect()}"
... />
- เชื่อมโยงเหตุการณ์การคลิกของ
end_game_button
กับเมธอดonGameFinish
()
ในGameViewModel
<Button
android:id="@+id/end_game_button"
...
android:onClick="@{() -> gameViewModel.onGameFinish()}"
... />
- ใน
GameFragment
ให้นําคําสั่งที่กําหนด Listener การคลิกออก และนําฟังก์ชันที่ Listener การคลิกออก คุณไม่จําเป็นต้องใช้อีก
รหัสที่จะนําออก:
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()
}
ขั้นตอนที่ 3: เพิ่มการเชื่อมโยงข้อมูลสําหรับ ScoreViewModel
ในขั้นตอนนี้ คุณจะเชื่อมโยง ScoreViewModel
กับไฟล์เลย์เอาต์ที่เกี่ยวข้อง score_fragment.xml
- ในไฟล์
score_fragment.xml
ให้เพิ่มตัวแปรการเชื่อมโยงของประเภทScoreViewModel
ขั้นตอนนี้คล้ายกับสิ่งที่คุณทําสําหรับGameViewModel
ด้านบน
<layout ...>
<data>
<variable
name="scoreViewModel"
type="com.example.android.guesstheword.screens.score.ScoreViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
- ใน
score_fragment.xml
ให้เพิ่มแอตทริบิวต์onClick
ลงในplay_again_button
กําหนดการเชื่อมโยง Listener และเรียกเมธอดonPlayAgain()
ในScoreViewModel
<Button
android:id="@+id/play_again_button"
...
android:onClick="@{() -> scoreViewModel.onPlayAgain()}"
... />
- ใน
ScoreFragment
ให้เริ่มต้นviewModel
ภายในonCreateView()
จากนั้นเริ่มต้นตัวแปรการเชื่อมโยงbinding.scoreViewModel
viewModel = ...
binding.scoreViewModel = viewModel
- ใน
ScoreFragment
ให้นําโค้ดที่ตั้งค่า Listener การคลิกสําหรับplayAgainButton
ออก หาก Android Studio แสดงข้อผิดพลาด โปรดทําความสะอาดและสร้างโปรเจ็กต์ใหม่
รหัสที่จะนําออก:
binding.playAgainButton.setOnClickListener { viewModel.onPlayAgain() }
- เรียกใช้แอป แอปควรจะทํางานเหมือนก่อนหน้านี้ แต่ตอนนี้มุมมองปุ่มจะสื่อสารกับออบเจ็กต์
ViewModel
โดยตรง มุมมองไม่สื่อสารผ่านเครื่องจัดการปุ่มในScoreFragment
แล้ว
การแก้ปัญหาข้อความแสดงข้อผิดพลาดการเชื่อมโยงข้อมูล
เมื่อแอปใช้การเชื่อมโยงข้อมูล กระบวนการคอมไพล์จะสร้างคลาสระดับกลางที่ใช้สําหรับการเชื่อมโยงข้อมูล แอปอาจมีข้อผิดพลาดที่ Android Studio ไม่ตรวจพบจนกว่าคุณจะพยายามคอมไพล์แอป คุณจึงไม่เห็นคําเตือนหรือโค้ดสีแดงขณะที่เขียนโค้ด แต่เมื่อคอมไพล์แล้ว คุณจะได้รับข้อผิดพลาดเกี่ยวกับการเข้ารหัสลับที่มาจากชั้นเรียนระดับกลางที่สร้างขึ้น
หากได้รับข้อความแสดงข้อผิดพลาดที่เข้ารหัส ให้ทําดังนี้
- พิจารณาข้อความในช่องสร้างของ Android Studio อย่างละเอียด หากเห็นสถานที่ที่ลงท้ายด้วย
databinding
แสดงว่าเกิดข้อผิดพลาดในการเชื่อมโยงข้อมูล - ในไฟล์ XML ของเลย์เอาต์ ให้ตรวจหาข้อผิดพลาดในแอตทริบิวต์
onClick
ที่ใช้การเชื่อมโยงข้อมูล ค้นหาฟังก์ชันที่นิพจน์แลมบ์ดาเรียกใช้ แล้วตรวจสอบว่ามีฟังก์ชันนั้นอยู่ - ในส่วน
<data>
ของ XML ให้ตรวจสอบการสะกดคําของตัวแปรการเชื่อมโยงข้อมูล
เช่น โปรดสะกดชื่อฟังก์ชัน onCorrect()
ที่สะกดผิดในค่าแอตทริบิวต์ต่อไปนี้
android:onClick="@{() -> gameViewModel.onCorrectx()}"
นอกจากนี้ โปรดสังเกตการสะกดคําผิดของ gameViewModel
ในส่วน <data>
ของไฟล์ XML ดังนี้
<data>
<variable
name="gameViewModelx"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
Android Studio ไม่ตรวจหาข้อผิดพลาดลักษณะนี้จนกว่าคุณจะคอมไพล์แอป จากนั้นคอมไพเลอร์จะแสดงข้อความแสดงข้อผิดพลาดต่อไปนี้
error: cannot find symbol import com.example.android.guesstheword.databinding.GameFragmentBindingImpl" symbol: class GameFragmentBindingImpl location: package com.example.android.guesstheword.databinding
การเชื่อมโยงข้อมูลทํางานได้ดีกับ LiveData
ที่ใช้กับออบเจ็กต์ ViewModel
เมื่อเพิ่มการเชื่อมโยงข้อมูลไปยังออบเจ็กต์ ViewModel
แล้ว คุณก็พร้อมที่จะรวม LiveData
แล้ว
ในงานนี้ คุณจะต้องเปลี่ยนแอป GuessTheWord เพื่อใช้ LiveData
เป็นแหล่งข้อมูลแบบผูกข้อมูลเพื่อแจ้ง UI เกี่ยวกับการเปลี่ยนแปลงในข้อมูลโดยไม่ต้องใช้เมธอดการสังเกตการณ์ LiveData
ขั้นตอนที่ 1: เพิ่มคําว่า LiveData ลงในไฟล์ Game_fragment.xml
ในขั้นตอนนี้ คุณจะเชื่อมโยงมุมมองข้อความปัจจุบันกับออบเจ็กต์ LiveData
ใน ViewModel
โดยตรง
- ใน
game_fragment.xml
ให้เพิ่มแอตทริบิวต์android:text
ลงในมุมมองข้อความword_text
ตั้งค่าเป็นออบเจ็กต์ LiveData
คือ word
จาก GameViewModel
โดยใช้ตัวแปรการเชื่อมโยง gameViewModel
<TextView
android:id="@+id/word_text"
...
android:text="@{gameViewModel.word}"
... />
สังเกตเห็นว่าคุณไม่จําเป็นต้องใช้ word.value
แต่คุณใช้ออบเจ็กต์ LiveData
จริงแทนได้ ออบเจ็กต์ LiveData
จะแสดงค่าปัจจุบันของ word
หากค่า word
เป็น Null ออบเจ็กต์ LiveData
จะแสดงสตริงที่ว่างเปล่า
- ใน
GameFragment
ในonCreateView()
หลังจากเริ่มต้นgameViewModel
ให้ตั้งค่ากิจกรรมปัจจุบันเป็นเจ้าของวงจรของตัวแปรbinding
การดําเนินการนี้จะกําหนดขอบเขตของออบเจ็กต์LiveData
ด้านบน ทําให้ออบเจ็กต์สามารถอัปเดตมุมมองในเลย์เอาต์โดยอัตโนมัติได้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
- ใน
GameFragment
ให้นําผู้สังเกตการณ์สําหรับword
ของLiveData
ออก
รหัสที่จะนําออก:
/** Setting up LiveData observation relationship **/
viewModel.word.observe(this, Observer { newWord ->
binding.wordText.text = newWord
})
- เรียกใช้แอปและเล่นเกม ตอนนี้กําลังอัปเดตคําปัจจุบันโดยไม่มีเมธอดการสังเกตการณ์ในตัวควบคุม UI
ขั้นตอนที่ 2: เพิ่มคะแนน LiveData ไปยังไฟล์ score_fragment.xml
ในขั้นตอนนี้ คุณจะเชื่อมโยง LiveData
score
เข้ากับมุมมองข้อความคะแนนใน Fragment คะแนน
- ใน
score_fragment.xml
ให้เพิ่มแอตทริบิวต์android:text
ลงในมุมมองข้อความคะแนน มอบหมายscoreViewModel.score
ให้กับแอตทริบิวต์text
เนื่องจากscore
เป็นจํานวนเต็ม โปรดแปลงเป็นสตริงโดยใช้String.valueOf()
<TextView
android:id="@+id/score_text"
...
android:text="@{String.valueOf(scoreViewModel.score)}"
... />
- ใน
ScoreFragment
หลังจากเริ่มต้นscoreViewModel
ให้ตั้งค่ากิจกรรมปัจจุบันเป็นเจ้าของวงจรของตัวแปรbinding
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
- ใน
ScoreFragment
ให้นําการสังเกตการณ์ออกสําหรับออบเจ็กต์score
รหัสที่จะนําออก:
// Add observer for score
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
- เรียกใช้แอปและเล่นเกม โปรดสังเกตว่าคะแนนใน Fragment คะแนนจะแสดงอย่างถูกต้อง โดยไม่มีข้อสังเกตในส่วนคะแนน
ขั้นตอนที่ 3: เพิ่มการจัดรูปแบบสตริงด้วยการเชื่อมโยงข้อมูล
ในเลย์เอาต์ คุณสามารถเพิ่มการจัดรูปแบบสตริงควบคู่ไปกับการเชื่อมโยงข้อมูลได้ ในงานนี้ คุณจะต้องจัดรูปแบบคําปัจจุบันเพื่อเพิ่มเครื่องหมายคําพูด คุณยังจัดรูปแบบสตริงคะแนนนําหน้าคะแนนปัจจุบันได้อีกด้วย ดังที่แสดงในรูปภาพต่อไปนี้
- ใน
string.xml
ให้เพิ่มสตริงต่อไปนี้ ซึ่งจะใช้ในการจัดรูปแบบมุมมองข้อความword
และscore
%s
และ%d
เป็นตัวยึดตําแหน่งสําหรับคําปัจจุบันและคะแนนปัจจุบัน
<string name="quote_format">\"%s\"</string>
<string name="score_format">Current Score: %d</string>
- ใน
game_fragment.xml
ให้อัปเดตแอตทริบิวต์text
ของมุมมองข้อความword_text
เพื่อใช้ทรัพยากรสตริงquote_format
ผ่านในgameViewModel.word
ซึ่งจะส่งผ่านคําปัจจุบันเป็นอาร์กิวเมนต์ไปยังสตริงการจัดรูปแบบ
<TextView
android:id="@+id/word_text"
...
android:text="@{@string/quote_format(gameViewModel.word)}"
... />
- จัดรูปแบบมุมมองข้อความ
score
ที่คล้ายกับword_text
ในgame_fragment.xml
ให้เพิ่มแอตทริบิวต์text
ในมุมมองข้อความscore_text
ใช้ทรัพยากรสตริงscore_format
ซึ่งใช้อาร์กิวเมนต์ตัวเลข 1 ค่าแทนด้วยตัวยึดตําแหน่ง%d
ส่งผ่านในออบเจ็กต์LiveData
คือscore
เป็นอาร์กิวเมนต์ในสตริงการจัดรูปแบบนี้
<TextView
android:id="@+id/score_text"
...
android:text="@{@string/score_format(gameViewModel.score)}"
... />
- ใน
GameFragment
คลาส ให้ลบโค้ดการสังเกตการณ์score
ภายในเมธอดonCreateView()
รหัสที่จะนําออก:
viewModel.score.observe(this, Observer { newScore ->
binding.scoreText.text = newScore.toString()
})
- ทําความสะอาด สร้างใหม่ และเรียกใช้แอป แล้วเล่นเกม โปรดสังเกตว่าคําปัจจุบันและคะแนนอยู่ในรูปแบบในหน้าจอเกม
ยินดีด้วย คุณได้รวม LiveData
และ ViewModel
เข้ากับการเชื่อมโยงข้อมูลในแอป วิธีนี้จะช่วยให้มุมมองในเลย์เอาต์สื่อสารกับ ViewModel
ได้โดยตรงโดยไม่ต้องใช้เครื่องจัดการคลิกในส่วนย่อย นอกจากนี้คุณยังใช้ออบเจ็กต์ LiveData
เป็นแหล่งที่มาของการเชื่อมโยงข้อมูลเพื่อแจ้ง UI โดยอัตโนมัติเกี่ยวกับการเปลี่ยนแปลงข้อมูล โดยไม่ต้องใช้เมธอดการสังเกตการณ์ LiveData
รายการ
โปรเจ็กต์ Android Studio: GuessTheWord
- ไลบรารีการเชื่อมโยงข้อมูลจะทํางานร่วมกับคอมโพเนนต์สถาปัตยกรรม Android เช่น
ViewModel
และLiveData
ได้อย่างราบรื่น - เลย์เอาต์ในแอปสามารถเชื่อมโยงกับข้อมูลในคอมโพเนนต์สถาปัตยกรรม ซึ่งช่วยให้คุณจัดการวงจรของตัวควบคุม UI และแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงในข้อมูลได้
การเชื่อมโยงข้อมูลพร็อพเพอร์ตี้ Model
- คุณเชื่อมโยง
ViewModel
กับเลย์เอาต์ได้โดยใช้การเชื่อมโยงข้อมูล - ออบเจ็กต์
ViewModel
มีข้อมูล UI อยู่ การส่งออบเจ็กต์ViewModel
ไปยังการเชื่อมโยงข้อมูลจะทําให้การสื่อสารบางอย่างระหว่างข้อมูลพร็อพเพอร์ตี้และออบเจ็กต์ViewModel
ทํางานโดยอัตโนมัติ
วิธีเชื่อมโยง ViewModel
กับเลย์เอาต์
- เพิ่มตัวแปรการเชื่อมโยงของข้อมูลประเภท
ViewModel
ในไฟล์เลย์เอาต์
<data>
<variable
name="gameViewModel"
type="com.example.android.guesstheword.screens.game.GameViewModel" />
</data>
- ในไฟล์
GameFragment
ให้ส่งGameViewModel
ไปยังการเชื่อมโยงข้อมูล
binding.gameViewModel = viewModel
การเชื่อมโยง Listener
- การเชื่อมโยง Listener คือนิพจน์การเชื่อมโยงในเลย์เอาต์ที่ทํางานเมื่อมีการเรียกเหตุการณ์การคลิก เช่น
onClick()
- การเชื่อมโยง Listener จะถูกเขียนเป็นนิพจน์แลมบ์ดา
- เมื่อใช้การเชื่อมโยง Listener คุณสามารถแทนที่ Listener การคลิกในตัวควบคุม UI ด้วย Listener การเชื่อมโยงในไฟล์เลย์เอาต์
- การเชื่อมโยงข้อมูลจะสร้าง Listener และตั้งค่า Listener ในข้อมูลพร็อพเพอร์ตี้
android:onClick="@{() -> gameViewModel.onSkip()}"
การเพิ่ม LiveData ไปยังการเชื่อมโยงข้อมูล
- คุณใช้ออบเจ็กต์
LiveData
เป็นแหล่งข้อมูลแบบผูกข้อมูลเพื่อแจ้ง UI โดยอัตโนมัติเกี่ยวกับการเปลี่ยนแปลงข้อมูลได้ - คุณสามารถเชื่อมโยงมุมมองกับออบเจ็กต์
LiveData
ในViewModel
ได้โดยตรง เมื่อLiveData
ในViewModel
อัปเดต มุมมองในเลย์เอาต์อาจอัปเดตโดยอัตโนมัติโดยไม่มีเมธอดการสังเกตการณ์ในตัวควบคุม UI
android:text="@{gameViewModel.word}"
- เพื่อให้การเชื่อมโยงข้อมูล
LiveData
ทํางานได้ ให้ตั้งค่ากิจกรรมปัจจุบัน (ตัวควบคุม UI) เป็นเจ้าของวงจรของตัวแปรbinding
ในตัวควบคุม UI
binding.lifecycleOwner = this
การจัดรูปแบบสตริงด้วยการเชื่อมโยงข้อมูล
- คุณสามารถเชื่อมโยงทรัพยากรสตริงกับตัวยึดตําแหน่ง เช่น
%s
สําหรับสตริงและ%d
สําหรับจํานวนเต็มโดยใช้การเชื่อมโยงข้อมูล - หากต้องการอัปเดตแอตทริบิวต์
text
ของข้อมูลพร็อพเพอร์ตี้ ให้ส่งผ่านออบเจ็กต์LiveData
เป็นอาร์กิวเมนต์ไปยังสตริงการจัดรูปแบบ
android:text="@{@string/quote_format(gameViewModel.word)}"
หลักสูตร Udacity:
เอกสารประกอบสําหรับนักพัฒนาซอฟต์แวร์ Android
ส่วนนี้จะอธิบายการบ้านและรายงานสําหรับนักเรียนที่ทํางานผ่าน Codelab นี้ซึ่งเป็นส่วนหนึ่งของหลักสูตรที่นําโดยผู้สอน สิ่งที่ผู้สอนต้องทํามีดังนี้
- มอบหมายการบ้านหากจําเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานทําการบ้าน
- ตัดเกรดการบ้าน
ผู้สอนจะใช้คําแนะนําเหล่านี้เท่าใดก็ได้หรือตามที่ต้องการก็ได้ และสามารถกําหนดให้การบ้านอื่นๆ ที่ตนคิดว่าเหมาะสมได้
หากคุณใช้ Codelab ด้วยตัวเอง ก็ให้ใช้การบ้านเพื่อทดสอบความรู้ของคุณได้
ตอบคําถามเหล่านี้
คำถามที่ 1
ข้อความใดต่อไปนี้ที่ไม่เป็นจริงเกี่ยวกับการเชื่อมโยงผู้ฟัง
- Listener การเชื่อมโยงคือนิพจน์การเชื่อมโยงที่จะทํางานเมื่อมีเหตุการณ์เกิดขึ้น
- การเชื่อมโยง Listener จะทํางานร่วมกับปลั๊กอิน Android Gradle ทุกเวอร์ชัน
- การเชื่อมโยง Listener จะถูกเขียนเป็นนิพจน์แลมบ์ดา
- การเชื่อมโยง Listener คล้ายกับการอ้างอิงเมธอด แต่ช่วยให้คุณสามารถเรียกใช้นิพจน์การเชื่อมโยงข้อมูลที่กําหนดเองได้
คำถามที่ 2
สมมติว่าแอปของคุณมีทรัพยากรสตริงนี้:<string name="generic_name">Hello %s</string>
ข้อใดต่อไปนี้เป็นไวยากรณ์ที่ถูกต้องสําหรับการจัดรูปแบบสตริงโดยใช้นิพจน์การเชื่อมโยงข้อมูล
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}"
คำถามที่ 3
นิพจน์การเชื่อมโยงผู้ฟังจะได้รับการประเมินและเรียกใช้เมื่อใด
- ข้อมูลที่เปลี่ยนแปลงของ
LiveData
มีการเปลี่ยนแปลง - เมื่อมีการสร้างกิจกรรมอีกครั้งโดยการเปลี่ยนแปลงการกําหนดค่า
- เมื่อมีเหตุการณ์อย่างเช่น
onClick()
เกิดขึ้น - เวลาที่กิจกรรมเข้าสู่พื้นหลัง
เริ่มบทเรียนถัดไป:
สําหรับลิงก์ไปยัง Codelab อื่นๆ ในหลักสูตรนี้ โปรดดูหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals