Codelab นี้เป็นส่วนหนึ่งของหลักสูตรหลักพื้นฐานของ Android Kotlin คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้หากทำตาม Codelab ตามลำดับ Codelab ของหลักสูตรทั้งหมดแสดงอยู่ในหน้า Landing Page ของ Codelab หลักพื้นฐานของ Android Kotlin
บทนำ
แอปส่วนใหญ่ที่ใช้รายการและตารางกริดซึ่งแสดงรายการจะอนุญาตให้ผู้ใช้โต้ตอบกับรายการ การแตะรายการจากลิสต์และดูรายละเอียดของรายการเป็นกรณีการใช้งานที่พบบ่อยมากสําหรับการโต้ตอบประเภทนี้ หากต้องการดำเนินการนี้ คุณสามารถเพิ่มเครื่องมือฟังการคลิกที่ตอบสนองต่อการแตะรายการของผู้ใช้โดยแสดงมุมมองรายละเอียด
ใน Codelab นี้ คุณจะเพิ่มการโต้ตอบลงใน RecyclerView
โดยต่อยอดจากแอปติดตามการนอนหลับเวอร์ชันขยายจาก Codelab ชุดก่อนหน้า
สิ่งที่คุณควรทราบอยู่แล้ว
- การสร้างอินเทอร์เฟซผู้ใช้พื้นฐานโดยใช้กิจกรรม Fragment และมุมมอง
- การไปยังส่วนย่อยต่างๆ และการใช้
safeArgs
เพื่อส่งข้อมูลระหว่างส่วนย่อย - ดูโมเดล โรงงานโมเดล การแปลง และ
LiveData
รวมถึง Observer ของโมเดล - วิธีสร้าง
Room
ฐานข้อมูล สร้างออบเจ็กต์การเข้าถึงข้อมูล (DAO) และกำหนดเอนทิตี - วิธีใช้โครูทีนสำหรับฐานข้อมูลและงานอื่นๆ ที่ใช้เวลานาน
- วิธีใช้
RecyclerView
พื้นฐานกับAdapter
,ViewHolder
และเลย์เอาต์รายการ - วิธีใช้การเชื่อมโยงข้อมูลสำหรับ
RecyclerView
- วิธีสร้างและใช้อะแดปเตอร์การเชื่อมโยงเพื่อเปลี่ยนรูปแบบข้อมูล
- วิธีใช้
GridLayoutManager
สิ่งที่คุณจะได้เรียนรู้
- วิธีทำให้รายการใน
RecyclerView
คลิกได้ ใช้เครื่องมือฟังการคลิกเพื่อไปยังมุมมองรายละเอียดเมื่อมีการคลิกรายการ
สิ่งที่คุณต้องดำเนินการ
- สร้างต่อจากแอป TrackMySleepQuality เวอร์ชันขยายจากโค้ดแล็บก่อนหน้าในชุดนี้
- เพิ่มเครื่องมือฟังการคลิกลงในรายการและเริ่มฟังการโต้ตอบของผู้ใช้ เมื่อแตะรายการ ระบบจะเรียกใช้การนำทางไปยัง Fragment ที่มีรายละเอียดเกี่ยวกับรายการที่คลิก โค้ดเริ่มต้นมีโค้ดสำหรับรายละเอียด Fragment รวมถึงโค้ดการนำทาง
แอปติดตามการนอนหลับเริ่มต้นมี 2 หน้าจอซึ่งแสดงด้วย Fragment ดังที่แสดงในรูปภาพด้านล่าง
หน้าจอแรกที่แสดงทางด้านซ้ายมีปุ่มสำหรับเริ่มและหยุดการติดตาม หน้าจอจะแสดงข้อมูลการนอนหลับบางส่วนของผู้ใช้ ปุ่มล้างจะลบข้อมูลทั้งหมดที่แอปเก็บรวบรวมไว้สำหรับผู้ใช้ออกอย่างถาวร หน้าจอที่ 2 ซึ่งแสดงทางด้านขวาใช้สำหรับเลือกคะแนนคุณภาพการนอนหลับ
แอปนี้ใช้สถาปัตยกรรมที่เรียบง่ายพร้อมตัวควบคุม UI, โมเดลมุมมอง และ LiveData
รวมถึงฐานข้อมูล Room
เพื่อจัดเก็บข้อมูลการนอนหลับ
ในโค้ดแล็บนี้ คุณจะเพิ่มความสามารถในการตอบสนองเมื่อผู้ใช้แตะรายการในตารางกริด ซึ่งจะแสดงหน้าจอรายละเอียดเหมือนกับหน้าจอด้านล่าง โค้ดสำหรับหน้าจอนี้ (Fragment, ViewModel และการนำทาง) จะมาพร้อมกับแอปเริ่มต้น และคุณจะใช้กลไกการจัดการการคลิก
ขั้นตอนที่ 1: ดาวน์โหลดแอปเริ่มต้น
- ดาวน์โหลดโค้ด RecyclerViewClickHandler-Starter จาก GitHub แล้วเปิดโปรเจ็กต์ใน Android Studio
- สร้างและเรียกใช้แอปติดตามการนอนหลับเริ่มต้น
[ไม่บังคับ] อัปเดตแอปหากต้องการใช้แอปจากโค้ดแล็บก่อนหน้า
หากคุณจะทำงานจากแอปเริ่มต้นที่ระบุไว้ใน GitHub สำหรับโค้ดแล็บนี้ ให้ข้ามไปยังขั้นตอนถัดไป
หากต้องการใช้แอปติดตามการนอนหลับที่คุณสร้างขึ้นใน Codelab ก่อนหน้าต่อไป ให้ทำตามวิธีการด้านล่างเพื่ออัปเดตแอปที่มีอยู่ให้มีโค้ดสำหรับรายละเอียดหน้าจอ Fragment
- แม้ว่าคุณจะใช้แอปที่มีอยู่ต่อไป แต่ให้รับโค้ด RecyclerViewClickHandler-Starter จาก GitHub เพื่อให้คุณคัดลอกไฟล์ได้
- คัดลอกไฟล์ทั้งหมดในแพ็กเกจ
sleepdetail
- ใน
layout
โฟลเดอร์ ให้คัดลอกไฟล์fragment_sleep_detail.xml
- คัดลอกเนื้อหาที่อัปเดตของ
navigation.xml
ซึ่งจะเพิ่มการนำทางสำหรับsleep_detail_fragment
- ใน
database
แพ็กเกจSleepDatabaseDao
ให้เพิ่มเมธอดgetNightWithId()
ใหม่
/**
* Selects and returns the night with given nightId.
*/
@Query("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
fun getNightWithId(key: Long): LiveData<SleepNight>
- ใน
res/values/strings
ให้เพิ่มทรัพยากรสตริงต่อไปนี้
<string name="close">Close</string>
- ล้างและสร้างแอปใหม่เพื่ออัปเดตการเชื่อมโยงข้อมูล
ขั้นตอนที่ 2: ตรวจสอบโค้ดสำหรับหน้าจอรายละเอียดการนอนหลับ
ในโค้ดแล็บนี้ คุณจะใช้ตัวแฮนเดิลการคลิกที่จะไปยัง Fragment ที่แสดงรายละเอียดเกี่ยวกับคืนที่นอนหลับที่คลิก โค้ดเริ่มต้นมี Fragment และกราฟการนำทางสำหรับ SleepDetailFragment
อยู่แล้ว เนื่องจากมีโค้ดจำนวนมาก และ Fragment กับการนำทางไม่ได้เป็นส่วนหนึ่งของ Codelab นี้ ทำความคุ้นเคยกับโค้ดต่อไปนี้
- ค้นหาแพ็กเกจ
sleepdetail
ในแอป แพ็กเกจนี้มี Fragment, ViewModel และ ViewModelFactory สำหรับ Fragment ที่แสดงรายละเอียดการนอนหลับ 1 คืน - ในแพ็กเกจ
sleepdetail
ให้เปิดและตรวจสอบโค้ดสำหรับSleepDetailViewModel
โมเดลมุมมองนี้ใช้คีย์สำหรับSleepNight
และ DAO ในตัวสร้าง
เนื้อหาของคลาสมีโค้ดเพื่อรับSleepNight
สำหรับคีย์ที่ระบุ และตัวแปรnavigateToSleepTracker
เพื่อควบคุมการนำทางกลับไปยังSleepTrackerFragment
เมื่อกดปุ่มปิด
ฟังก์ชันgetNightWithId()
จะแสดงผลLiveData<SleepNight>
และกำหนดไว้ในSleepDatabaseDao
(ในแพ็กเกจdatabase
) - ในแพ็กเกจ
sleepdetail
ให้เปิดและตรวจสอบโค้ดสำหรับSleepDetailFragment
โปรดสังเกตการตั้งค่าการเชื่อมโยงข้อมูล, View Model และ Observer สำหรับการนำทาง - ในแพ็กเกจ
sleepdetail
ให้เปิดและตรวจสอบโค้ดสำหรับSleepDetailViewModelFactory
- ตรวจสอบ
fragment_sleep_detail.xml
ในโฟลเดอร์เลย์เอาต์ โปรดสังเกตตัวแปรsleepDetailViewModel
ที่กำหนดไว้ในแท็ก<data>
เพื่อรับข้อมูลที่จะแสดงในแต่ละมุมมองจาก View Model
เลย์เอาต์มีConstraintLayout
ที่มีImageView
สำหรับคุณภาพการนอนหลับTextView
สำหรับการให้คะแนนคุณภาพTextView
สำหรับระยะเวลาการนอนหลับ และButton
เพื่อปิดรายละเอียด Fragment - เปิดไฟล์
navigation.xml
สำหรับsleep_tracker_fragment
ให้สังเกตการดำเนินการใหม่สำหรับsleep_detail_fragment
การดำเนินการใหม่action_sleep_tracker_fragment_to_sleepDetailFragment
คือการไปยังส่วนต่างๆ จาก Fragment เครื่องมือติดตามการนอนหลับไปยังหน้าจอรายละเอียด
ในงานนี้ คุณจะอัปเดต RecyclerView
เพื่อตอบสนองต่อการแตะของผู้ใช้โดยแสดงหน้าจอรายละเอียดสำหรับรายการที่แตะ
การรับและการจัดการคลิกเป็นงาน 2 ส่วน โดยก่อนอื่นคุณต้องรับฟังและรับคลิก รวมถึงพิจารณาว่ามีการคลิกรายการใด จากนั้นคุณต้องตอบสนองต่อการคลิกด้วยการดำเนินการ
แล้วที่ไหนเหมาะที่สุดที่จะเพิ่มเครื่องมือฟังการคลิกสำหรับแอปนี้
SleepTrackerFragment
มีมุมมองมากมาย ดังนั้นการฟังเหตุการณ์คลิกที่ระดับ Fragment จะไม่บอกว่ามีการคลิกรายการใด และจะไม่บอกด้วยว่าเป็นการคลิกรายการหรือองค์ประกอบ UI อื่นๆ- การฟังที่ระดับ
RecyclerView
ทำให้ยากที่จะระบุได้อย่างแม่นยำว่าผู้ใช้คลิกรายการใดในรายการ - อัตราที่ดีที่สุดในการรับข้อมูลเกี่ยวกับรายการที่คลิกคือในออบเจ็กต์
ViewHolder
เนื่องจากแสดงถึงรายการในลิสต์ 1 รายการ
แม้ว่า ViewHolder
จะเป็นที่ที่เหมาะสำหรับการฟังการคลิก แต่โดยปกติแล้วไม่ใช่ที่ที่เหมาะสมในการจัดการการคลิก แล้วที่ใดคือที่ที่ดีที่สุดในการจัดการคลิก
Adapter
จะแสดงรายการข้อมูลในมุมมองเพื่อให้คุณจัดการการคลิกในอแดปเตอร์ได้ อย่างไรก็ตาม หน้าที่ของ Adapter คือการปรับข้อมูลเพื่อแสดง ไม่ใช่การจัดการตรรกะของแอป- โดยปกติแล้ว คุณควรจัดการการคลิกใน
ViewModel
เนื่องจากViewModel
มีสิทธิ์เข้าถึงข้อมูลและตรรกะในการพิจารณาสิ่งที่ต้องเกิดขึ้นเพื่อตอบสนองต่อการคลิก
ขั้นตอนที่ 1: สร้างเครื่องมือฟังการคลิกและเรียกใช้จากเลย์เอาต์ของรายการ
- ในโฟลเดอร์
sleeptracker
ให้เปิด SleepNightAdapter.kt - ที่ส่วนท้ายของไฟล์ ในระดับบนสุด ให้สร้างคลาส Listener ใหม่
SleepNightListener
class SleepNightListener() {
}
- เพิ่ม
onClick()
ฟังก์ชันภายในSleepNightListener
คลาส เมื่อมีการคลิกมุมมองที่แสดงรายการ ระบบจะเรียกใช้onClick()
ฟังก์ชันนี้ (คุณจะตั้งค่าพร็อพเพอร์ตี้android:onClick
ของข้อมูลพร็อพเพอร์ตี้ในภายหลังเป็นฟังก์ชันนี้)
class SleepNightListener() {
fun onClick() =
}
- เพิ่มอาร์กิวเมนต์ฟังก์ชัน
night
ของประเภทSleepNight
ไปยังonClick()
มุมมองทราบว่ากำลังแสดงรายการใด และต้องส่งต่อข้อมูลดังกล่าวเพื่อจัดการการคลิก
class SleepNightListener() {
fun onClick(night: SleepNight) =
}
- หากต้องการกำหนดว่า
onClick()
ทำอะไร ให้ระบุการเรียกกลับclickListener
ในตัวสร้างของSleepNightListener
แล้วกำหนดให้onClick()
การตั้งชื่อ Lambda ที่จัดการการคลิกclickListener
จะช่วยให้ติดตามได้เมื่อมีการส่งผ่านระหว่างคลาส การเรียกกลับclickListener
ต้องการเพียงnight.nightId
เพื่อเข้าถึงข้อมูลจากฐานข้อมูลSleepNightListener
คลาสที่เสร็จสมบูรณ์แล้วควรมีลักษณะเหมือนโค้ดด้านล่าง
class SleepNightListener(val clickListener: (sleepId: Long) -> Unit) {
fun onClick(night: SleepNight) = clickListener(night.nightId)
}
- เปิด list_item_sleep_night.xml.
- ภายในบล็อก
data
ให้เพิ่มตัวแปรใหม่เพื่อให้คลาสSleepNightListener
พร้อมใช้งานผ่านการเชื่อมโยงข้อมูล ตั้ง<variable>
ใหม่เป็นname
ของclickListener.
ตั้งค่าtype
เป็นชื่อที่สมบูรณ์ของคลาสcom.example.android.trackmysleepquality.sleeptracker.SleepNightListener
ดังที่แสดงด้านล่าง ตอนนี้คุณเข้าถึงฟังก์ชันonClick()
ในSleepNightListener
จากเลย์เอาต์นี้ได้แล้ว
<variable
name="clickListener"
type="com.example.android.trackmysleepquality.sleeptracker.SleepNightListener" />
- หากต้องการฟังการคลิกส่วนใดส่วนหนึ่งของรายการนี้ ให้เพิ่มแอตทริบิวต์
android:onClick
ลงในConstraintLayout
ตั้งค่าแอตทริบิวต์เป็นclickListener:onClick(sleep)
โดยใช้ Lambda การเชื่อมโยงข้อมูล ดังที่แสดงด้านล่าง
android:onClick="@{() -> clickListener.onClick(sleep)}"
ขั้นตอนที่ 2: ส่งเครื่องมือฟังการคลิกไปยังตัวยึดมุมมองและออบเจ็กต์การเชื่อมโยง
- เปิด SleepNightAdapter.kt
- แก้ไขตัวสร้างของคลาส
SleepNightAdapter
เพื่อรับval clickListener: SleepNightListener
เมื่ออะแดปเตอร์เชื่อมโยงViewHolder
จะต้องระบุเครื่องมือฟังการคลิกนี้
class SleepNightAdapter(val clickListener: SleepNightListener):
ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
- ใน
onBindViewHolder()
ให้อัปเดตการเรียกไปยังholder.bind()
เพื่อส่งต่อ Listener การคลิกไปยังViewHolder
ด้วย คุณจะได้รับข้อผิดพลาดของคอมไพเลอร์เนื่องจากคุณเพิ่มพารามิเตอร์ลงในการเรียกฟังก์ชัน
holder.bind(getItem(position)!!, clickListener)
- เพิ่มพารามิเตอร์
clickListener
ลงในbind()
โดยวางเคอร์เซอร์บนข้อผิดพลาด แล้วกดAlt+Enter
(Windows) หรือOption+Enter
(Mac) บนข้อผิดพลาดเพื่อดูรายละเอียด ดังที่แสดงในภาพหน้าจอด้านล่าง
- ในคลาส
ViewHolder
ภายในฟังก์ชันbind()
ให้กำหนด Listener การคลิกให้กับออบเจ็กต์binding
คุณเห็นข้อผิดพลาดเนื่องจากต้องอัปเดตออบเจ็กต์การเชื่อมโยง
binding.clickListener = clickListener
- หากต้องการอัปเดตการเชื่อมโยงข้อมูล ให้ล้างและสร้างใหม่โปรเจ็กต์ (คุณอาจต้องล้างแคชด้วย) ดังนั้น คุณจึงนำเครื่องมือฟังการคลิกจากตัวสร้างอแดปเตอร์ และส่งไปยังตัวยึดมุมมองและไปยังออบเจ็กต์การเชื่อมโยง
ขั้นตอนที่ 3: แสดงข้อความป๊อปอัปเมื่อแตะรายการ
ตอนนี้คุณมีโค้ดที่ใช้บันทึกการคลิกแล้ว แต่ยังไม่ได้ติดตั้งใช้งานสิ่งที่เกิดขึ้นเมื่อมีการแตะรายการในลิสต์ การตอบกลับที่ง่ายที่สุดคือการแสดงข้อความป๊อปอัปที่แสดง nightId
เมื่อมีการคลิกรายการ ซึ่งจะยืนยันว่าเมื่อมีการคลิกรายการ ระบบจะบันทึกและส่งต่อ nightId
ที่ถูกต้อง
- เปิด SleepTrackerFragment.kt
- ใน
onCreateView()
ให้ค้นหาตัวแปรadapter
โปรดสังเกตว่าระบบแสดงข้อผิดพลาดเนื่องจากตอนนี้คาดหวังพารามิเตอร์ Listener การคลิก - กำหนดเครื่องมือฟังการคลิกโดยส่งผ่าน Lambda ไปยัง
SleepNightAdapter
Lambda อย่างง่ายนี้จะแสดงข้อความโทสต์ที่แสดงnightId
ดังที่แสดงด้านล่าง คุณจะต้องนำเข้าToast
คำจำกัดความที่อัปเดตแล้วฉบับสมบูรณ์มีดังนี้
val adapter = SleepNightAdapter(SleepNightListener { nightId ->
Toast.makeText(context, "${nightId}", Toast.LENGTH_LONG).show()
})
- เรียกใช้แอป แตะรายการ และตรวจสอบว่ารายการแสดงข้อความป๊อปอัปพร้อม
nightId
ที่ถูกต้อง เนื่องจากรายการมีค่าnightId
เพิ่มขึ้น และแอปจะแสดงคืนล่าสุดก่อน รายการที่มีค่าnightId
ต่ำสุดจึงอยู่ด้านล่างของรายการ
ในงานนี้ คุณจะเปลี่ยนลักษณะการทำงานเมื่อมีการคลิกรายการใน RecyclerView
เพื่อให้แอปไปยังรายละเอียด Fragment ที่แสดงข้อมูลเพิ่มเติมเกี่ยวกับคืนที่คลิกแทนที่จะแสดงข้อความ Toast
ขั้นตอนที่ 1: ไปที่หน้าเว็บเมื่อคลิก
ในขั้นตอนนี้ แทนที่จะแสดงเพียงข้อความป๊อปอัป คุณจะเปลี่ยน Lambda ของเครื่องมือฟังการคลิกใน onCreateView()
ของ SleepTrackerFragment
เพื่อส่ง nightId
ไปยัง SleepTrackerViewModel
และทริกเกอร์การนำทางไปยัง SleepDetailFragment
กำหนดฟังก์ชันตัวแฮนเดิลการคลิก
- เปิด SleepTrackerViewModel.kt
- ภายใน
SleepTrackerViewModel
ให้กําหนดonSleepNightClicked()
ฟังก์ชันตัวแฮนเดิลการคลิกที่ส่วนท้าย
fun onSleepNightClicked(id: Long) {
}
- ภายใน
onSleepNightClicked()
ให้ทริกเกอร์การนำทางโดยตั้งค่า_navigateToSleepDetail
เป็นid
ที่ส่งมาของคืนที่คลิก
fun onSleepNightClicked(id: Long) {
_navigateToSleepDetail.value = id
}
- นำ
_navigateToSleepDetail
มาใช้ กำหนดprivate MutableLiveData
สำหรับสถานะการนำทางเช่นเดียวกับที่เคยทำ และมีval
ที่รับได้แบบสาธารณะ
private val _navigateToSleepDetail = MutableLiveData<Long>()
val navigateToSleepDetail
get() = _navigateToSleepDetail
- กำหนดวิธีการเรียกใช้หลังจากที่แอปนำทางเสร็จแล้ว ตั้งชื่อว่า
onSleepDetailNavigated()
และตั้งค่าเป็นnull
fun onSleepDetailNavigated() {
_navigateToSleepDetail.value = null
}
เพิ่มโค้ดเพื่อเรียกตัวแฮนเดิลการคลิก
- เปิด SleepTrackerFragment.kt แล้วเลื่อนลงไปที่โค้ดที่สร้างอแดปเตอร์และกำหนด
SleepNightListener
เพื่อแสดงข้อความ Toast
val adapter = SleepNightAdapter(SleepNightListener { nightId ->
Toast.makeText(context, "${nightId}", Toast.LENGTH_LONG).show()
})
- เพิ่มโค้ดต่อไปนี้ใต้ข้อความป๊อปอัปเพื่อเรียกตัวแฮนเดิลการคลิก
onSleepNighClicked()
ในsleepTrackerViewModel
เมื่อมีการแตะรายการ ส่งในnightId
เพื่อให้ ViewModel รู้ว่าควรรับคืนการนอนหลับคืนใด ซึ่งจะทำให้เกิดข้อผิดพลาดเนื่องจากคุณยังไม่ได้กำหนดonSleepNightClicked()
คุณจะเก็บ แสดงความคิดเห็น หรือลบข้อความแจ้งก็ได้ตามต้องการ
sleepTrackerViewModel.onSleepNightClicked(nightId)
เพิ่มโค้ดเพื่อสังเกตการคลิก
- เปิด SleepTrackerFragment.kt
- ใน
onCreateView()
เหนือประกาศของmanager
ให้เพิ่มโค้ดเพื่อสังเกตnavigateToSleepDetail
LiveData
ใหม่ เมื่อnavigateToSleepDetail
เปลี่ยนแปลง ให้ไปที่SleepDetailFragment
โดยส่งnight
แล้วเรียกใช้onSleepDetailNavigated()
หลังจากนั้น เนื่องจากคุณเคยทำสิ่งนี้ในโค้ดแล็บก่อนหน้านี้แล้ว เราจึงขอเสนอโค้ดดังนี้
sleepTrackerViewModel.navigateToSleepDetail.observe(this, Observer { night ->
night?.let {
this.findNavController().navigate(
SleepTrackerFragmentDirections
.actionSleepTrackerFragmentToSleepDetailFragment(night))
sleepTrackerViewModel.onSleepDetailNavigated()
}
})
- เรียกใช้โค้ด คลิกที่รายการ แล้วแอปก็ขัดข้อง
จัดการค่า Null ใน Binding Adapter ดังนี้
- เรียกใช้แอปอีกครั้งในโหมดแก้ไขข้อบกพร่อง แตะรายการ แล้วกรองบันทึกเพื่อแสดงข้อผิดพลาด โดยจะแสดง Stack Trace ซึ่งรวมถึงข้อมูลที่คล้ายกับข้อมูลด้านล่าง
Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter item
ขออภัยที่สแต็กเทรซไม่ได้ระบุอย่างชัดเจนว่าข้อผิดพลาดนี้เกิดขึ้นที่ใด ข้อเสียอย่างหนึ่งของการเชื่อมโยงข้อมูลคือการทำให้แก้ไขข้อบกพร่องของโค้ดได้ยากขึ้น แอปขัดข้องเมื่อคุณคลิกรายการ และโค้ดใหม่มีไว้เพื่อจัดการการคลิกเท่านั้น
อย่างไรก็ตาม กลไกการจัดการคลิกแบบใหม่นี้ทำให้ตอนนี้ Binding Adapter สามารถเรียกใช้ด้วยค่า null
สำหรับ item
ได้แล้ว โดยเฉพาะอย่างยิ่ง เมื่อแอปเริ่มต้น LiveData
จะเริ่มต้นเป็น null
คุณจึงต้องเพิ่มการตรวจสอบค่า Null ลงในแต่ละอแดปเตอร์
- ใน
BindingUtils.kt
ให้เปลี่ยนประเภทอาร์กิวเมนต์item
เป็น Nullable สำหรับ Binding Adapter แต่ละรายการ แล้วห่อเนื้อหาด้วยitem?.let{...}
เช่น อะแดปเตอร์สำหรับsleepQualityString
จะมีลักษณะดังนี้ เปลี่ยนอแดปเตอร์อื่นๆ ในลักษณะเดียวกัน
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight?) {
item?.let {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
}
- เรียกใช้แอป แตะรายการ แล้วมุมมองรายละเอียดจะเปิดขึ้น
โปรเจ็กต์ Android Studio: RecyclerViewClickHandler
หากต้องการให้รายการใน RecyclerView
ตอบสนองต่อการคลิก ให้แนบเครื่องมือฟังการคลิกกับรายการใน ViewHolder
และจัดการการคลิกใน ViewModel
หากต้องการให้รายการใน RecyclerView
ตอบสนองต่อการคลิก คุณต้องทำดังนี้
- สร้างคลาส Listener ที่ใช้ Lambda และกำหนดให้กับฟังก์ชัน
onClick()
class SleepNightListener(val clickListener: (sleepId: Long) -> Unit) {
fun onClick(night: SleepNight) = clickListener(night.nightId)
}
- ตั้งค่าเครื่องมือฟังการคลิกในมุมมอง
android:onClick="@{() -> clickListener.onClick(sleep)}"
- ส่งเครื่องมือฟังการคลิกไปยังตัวสร้างอะแดปเตอร์ ไปยังตัวยึดมุมมอง และเพิ่มลงในออบเจ็กต์การเชื่อมโยง
class SleepNightAdapter(val clickListener: SleepNightListener):
ListAdapter<DataItem, RecyclerView.ViewHolder>(SleepNightDiffCallback()
holder.bind(getItem(position)!!, clickListener)
binding.clickListener = clickListener
- ใน Fragment ที่แสดง RecyclerView ซึ่งคุณสร้าง Adapter ให้กำหนดเครื่องมือฟังการคลิกโดยส่ง Lambda ไปยัง Adapter
val adapter = SleepNightAdapter(SleepNightListener { nightId ->
sleepTrackerViewModel.onSleepNightClicked(nightId)
})
- ใช้ตัวแฮนเดิลการคลิกใน ViewModel สําหรับการคลิกรายการในลิสต์ โดยทั่วไปแล้วการคลิกนี้จะทําให้เกิดการไปยังส่วนย่อยรายละเอียด
หลักสูตร Udacity:
เอกสารประกอบสำหรับนักพัฒนาแอป Android
ส่วนนี้แสดงรายการการบ้านที่เป็นไปได้สำหรับนักเรียน/นักศึกษาที่กำลังทำ Codelab นี้เป็นส่วนหนึ่งของหลักสูตรที่สอนโดยผู้สอน ผู้สอนมีหน้าที่ดำเนินการต่อไปนี้
- มอบหมายการบ้านหากจำเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานที่ได้รับมอบหมาย
- ให้คะแนนงานการบ้าน
ผู้สอนสามารถใช้คำแนะนำเหล่านี้ได้มากน้อยตามที่ต้องการ และควรมีอิสระในการมอบหมายการบ้านอื่นๆ ที่เห็นว่าเหมาะสม
หากคุณกำลังทำ Codelab นี้ด้วยตนเอง โปรดใช้แบบฝึกหัดเหล่านี้เพื่อทดสอบความรู้ของคุณ
ตอบคำถามต่อไปนี้
คำถามที่ 1
สมมติว่าแอปของคุณมี RecyclerView
ที่แสดงรายการในช็อปปิ้งลิสต์ แอปของคุณยังกำหนดคลาสตัวฟังการคลิกด้วย
class ShoppingListItemListener(val clickListener: (itemId: Long) -> Unit) {
fun onClick(cartItem: CartItem) = clickListener(cartItem.itemId)
}
คุณจะทำให้ ShoppingListItemListener
พร้อมใช้งานกับการเชื่อมโยงข้อมูลได้อย่างไร เลือกหนึ่งรายการ
▢ ในไฟล์เลย์เอาต์ที่มี RecyclerView
ที่แสดงรายการช็อปปิ้ง ให้เพิ่มตัวแปร <data>
สำหรับ ShoppingListItemListener
▢ ในไฟล์เลย์เอาต์ที่กำหนดเลย์เอาต์สำหรับแถวเดียวในรายการช็อปปิ้ง ให้เพิ่มตัวแปร <data>
สำหรับ ShoppingListItemListener
▢ ในคลาส ShoppingListItemListener
ให้เพิ่มฟังก์ชันเพื่อเปิดใช้การเชื่อมโยงข้อมูล
fun onBinding (cartItem: CartItem) {dataBindingEnable(true)}
▢ ในคลาส ShoppingListItemListener
ภายในฟังก์ชัน onClick()
ให้เพิ่มการเรียกเพื่อเปิดใช้การเชื่อมโยงข้อมูล
fun onClick(cartItem: CartItem) = {
clickListener(cartItem.itemId)
dataBindingEnable(true)
}
คำถามที่ 2
คุณจะเพิ่มแอตทริบิวต์ android:onClick
ที่ทำให้สินค้าใน RecyclerView
ตอบสนองต่อการคลิกได้ที่ใด เลือกได้มากกว่า 1 ข้อ
▢ ในไฟล์เลย์เอาต์ที่แสดง RecyclerView
ให้เพิ่มลงใน <androidx.recyclerview.widget.RecyclerView>
▢ เพิ่มลงในไฟล์เลย์เอาต์ของรายการในแถว หากต้องการให้ทั้งรายการคลิกได้ ให้เพิ่มรายการลงในมุมมองระดับบนที่มีรายการในแถว
▢ เพิ่มลงในไฟล์เลย์เอาต์ของรายการในแถว หากต้องการให้ TextView
รายการเดียวในรายการคลิกได้ ให้เพิ่มลงใน <TextView>
▢ เพิ่มลงในไฟล์เลย์เอาต์สำหรับ MainActivity
เสมอ
เริ่มบทเรียนถัดไป: