Codelab นี้เป็นส่วนหนึ่งของหลักสูตรพื้นฐานเกี่ยวกับ Kotlin ใน Android คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้ หากทํางานผ่าน Codelab ตามลําดับ Codelab ของหลักสูตรทั้งหมดจะแสดงอยู่ในหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals
บทนำ
ใน Codelab ก่อนหน้า คุณได้อัปเดตแอป TrackMySleepคุณภาพ เพื่อแสดงข้อมูลเกี่ยวกับคุณภาพการนอนหลับใน RecyclerView
เทคนิคที่ได้เรียนรู้เมื่อสร้าง RecyclerView
แรกเพียงพอสําหรับ RecyclerViews
ส่วนใหญ่ที่แสดงรายการแบบง่ายที่ไม่ใหญ่เกินไป อย่างไรก็ตาม มีเทคนิคหลายอย่างที่ทําให้ RecyclerView
มีประสิทธิภาพมากขึ้นสําหรับรายการขนาดใหญ่และช่วยให้ดูแลรักษาโค้ดและขยายได้ง่ายขึ้นสําหรับรายการและตารางกริดที่ซับซ้อน
ใน Codelab นี้ คุณสร้างในแอปเครื่องมือติดตามการนอนหลับจาก Codelab ก่อนหน้า ดูวิธีที่มีประสิทธิภาพมากขึ้นในการอัปเดตรายการข้อมูลการนอนหลับ และดูวิธีใช้การเชื่อมโยงข้อมูลกับ RecyclerView
(หากไม่มีแอปจาก Codelab ก่อนหน้า ก็ดาวน์โหลดโค้ดเริ่มต้นสําหรับ Codelab นี้ได้)
สิ่งที่ควรทราบอยู่แล้ว
- การสร้างอินเทอร์เฟซผู้ใช้ขั้นพื้นฐานโดยใช้กิจกรรม ส่วนย่อย และการดู
- ไปยังส่วนต่างๆ ระหว่างส่วนย่อยและใช้
safeArgs
เพื่อส่งข้อมูลระหว่างส่วนย่อย - ดูโมเดล ดูโรงงานของโมเดล การเปลี่ยนรูปแบบ และ
LiveData
และการสังเกตการณ์ - วิธีสร้างฐานข้อมูล
Room
, สร้าง DAO และกําหนดเอนทิตี - วิธีใช้โครูทีนสําหรับฐานข้อมูลและงานอื่นๆ ที่ใช้เวลานาน
- วิธีใช้
RecyclerView
พื้นฐานด้วยAdapter
,ViewHolder
และเลย์เอาต์รายการ
สิ่งที่คุณจะได้เรียนรู้
- วิธีใช้
DiffUtil
เพื่ออัปเดตรายการที่แสดงโดยRecyclerView
อย่างมีประสิทธิภาพ - วิธีใช้การเชื่อมโยงข้อมูลกับ
RecyclerView
- วิธีใช้อะแดปเตอร์การเชื่อมโยงเพื่อเปลี่ยนรูปแบบข้อมูล
สิ่งที่คุณจะทํา
- สร้างจากแอป TrackMySleepคุณภาพ จาก Codelab ก่อนหน้าในชุดนี้
- อัปเดต
SleepNightAdapter
เพื่ออัปเดตรายการอย่างมีประสิทธิภาพโดยใช้DiffUtil
- ใช้งานการเชื่อมโยงข้อมูลสําหรับ
RecyclerView
โดยใช้อะแดปเตอร์การเชื่อมโยงในการแปลงข้อมูล
แอปติดตามการนอนหลับมี 2 หน้าจอที่แสดงด้วยส่วนย่อยดังที่แสดงในภาพด้านล่าง
หน้าจอแรกที่แสดงทางด้านซ้ายมีปุ่มสําหรับเริ่มต้นและหยุดติดตาม หน้าจอแสดงข้อมูลการนอนหลับของผู้ใช้บางส่วน ปุ่มล้างจะลบข้อมูลทั้งหมดที่แอปรวบรวมให้กับผู้ใช้อย่างถาวร หน้าจอที่ 2 ที่แสดงทางด้านขวาคือการเลือกคะแนนคุณภาพการนอนหลับ
แอปนี้ออกแบบมาเพื่อใช้ตัวควบคุม UI, ViewModel
และ LiveData
และฐานข้อมูล Room
เพื่อคงข้อมูลการนอนหลับไว้
ข้อมูลการนอนหลับจะแสดงใน RecyclerView
ใน Codelab นี้ คุณสร้างส่วน DiffUtil
และการเชื่อมโยงข้อมูลสําหรับ RecyclerView
หลังจาก Codelab นี้ แอปจะมีลักษณะเหมือนเดิมทุกประการ แต่จะมีประสิทธิภาพมากขึ้น รวมทั้งปรับขนาดและดูแลรักษาได้ง่ายขึ้น
คุณจะใช้แอป SleepTracker ต่อไปจาก Codelab ก่อนหน้าหรือดาวน์โหลดแอป RecyclerViewDiffUtilDataBinding-Starter จาก GitHub ได้
- หากจําเป็น ให้ดาวน์โหลดแอป RecyclerViewDiffUtilDataBinding-Starter จาก GitHub และเปิดโปรเจ็กต์ใน Android Studio
- เรียกใช้แอป
- เปิดไฟล์
SleepNightAdapter.kt
- ตรวจสอบโค้ดเพื่อทําความคุ้นเคยกับโครงสร้างของแอป ดูแผนภาพด้านล่างเพื่อดูสรุปการใช้
RecyclerView
กับรูปแบบอะแดปเตอร์เพื่อแสดงข้อมูลการนอนหลับให้กับผู้ใช้
- แอปจะสร้างรายการออบเจ็กต์
SleepNight
จากอินพุตของผู้ใช้ วัตถุSleepNight
แต่ละรายการแสดงถึงการนอนหลับ 1 คืน ระยะเวลา และคุณภาพ SleepNightAdapter
จะปรับรายการออบเจ็กต์SleepNight
ให้เป็นข้อมูลที่RecyclerView
ใช้และแสดงได้- อะแดปเตอร์
SleepNightAdapter
จะสร้างViewHolders
ซึ่งประกอบด้วยข้อมูลพร็อพเพอร์ตี้ ข้อมูล และข้อมูลเมตาสําหรับมุมมองการรีไซเคิลเพื่อแสดงข้อมูล RecyclerView
ใช้SleepNightAdapter
เพื่อระบุจํานวนรายการที่จะแสดง (getItemCount()
)RecyclerView
ใช้onCreateViewHolder()
และonBindViewHolder()
เพื่อให้ผู้ถือข้อมูลพร็อพเพอร์ตี้ได้ดูข้อมูล
เมธอดการแจ้งเตือน dataDataSetChanged() ไม่มีประสิทธิภาพ
หากต้องการแจ้ง RecyclerView
ว่ารายการมีการเปลี่ยนแปลงและจําเป็นต้องอัปเดต รหัสปัจจุบันจะเรียก notifyDataSetChanged()
ใน SleepNightAdapter
ดังที่แสดงด้านล่าง
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
}
อย่างไรก็ตาม notifyDataSetChanged()
จะบอก RecyclerView
ว่ารายการทั้งหมดอาจไม่ถูกต้อง ด้วยเหตุนี้ RecyclerView
จึงจะรวมและวาดทุกรายการในรายการอีกครั้ง รวมถึงรายการที่ไม่แสดงบนหน้าจอ การดําเนินการนี้เป็นขั้นตอนที่ไม่จําเป็น สําหรับรายการขนาดใหญ่หรือที่ซับซ้อน กระบวนการนี้อาจใช้เวลานานกว่านั้นจนกว่าจอแสดงผลจะกะพริบหรือกระตุกเมื่อผู้ใช้เลื่อนดูรายการ
หากต้องการแก้ไขปัญหานี้ คุณสามารถบอก RecyclerView
ว่ามีอะไรเปลี่ยนแปลงบ้าง จากนั้น RecyclerView
จะอัปเดตได้เฉพาะมุมมองที่เปลี่ยนบนหน้าจอเท่านั้น
RecyclerView
มี API แบบสมบูรณ์สําหรับการอัปเดตองค์ประกอบเดียว คุณอาจใช้ notifyItemChanged()
เพื่อแจ้ง RecyclerView
ว่ารายการมีการเปลี่ยนแปลง และใช้ฟังก์ชันที่คล้ายกันสําหรับรายการที่เพิ่ม นําออก หรือย้ายแล้วได้ โดยคุณอาจทําด้วยตนเองทั้งหมด แต่งานนั้นอาจไม่ใช่เรื่องเล็กๆ และอาจใช้โค้ดเพียงเล็กน้อย
โชคดีที่ยังมีวิธีที่ดีกว่า
DiffUtil มีประสิทธิภาพและทํางานอย่างหนักเพื่อคุณ
RecyclerView
มีคลาสชื่อ DiffUtil
ซึ่งมีไว้สําหรับการคํานวณความแตกต่างระหว่าง 2 รายการ DiffUtil
ใช้รายการเก่าและรายการใหม่เพื่อดูสิ่งที่ต่างไปจากเดิม ซึ่งจะค้นหารายการที่เพิ่ม นําออก หรือเปลี่ยนแปลง จากนั้นจะใช้อัลกอริทึมที่เรียกว่า Eugene W. Myers'อัลกอริทึมอัลกอริทึมเพื่อหาจํานวนการเปลี่ยนแปลงขั้นต่ําจากรายการเก่าเพื่อสร้างรายการใหม่
เมื่อ DiffUtil
ทราบถึงสิ่งที่เปลี่ยนแปลงแล้ว RecyclerView
จะใช้ข้อมูลนั้นเพื่ออัปเดตเฉพาะรายการที่เปลี่ยนแปลง เพิ่ม นําออก หรือย้าย ซึ่งมีประสิทธิภาพมากกว่าการทําซ้ําทั้งรายการ
ในงานนี้ คุณจะต้องอัปเกรด SleepNightAdapter
เพื่อใช้ DiffUtil
เพื่อเพิ่มประสิทธิภาพ RecyclerView
สําหรับการเปลี่ยนแปลงข้อมูล
ขั้นตอนที่ 1: ใช้ SleepNightDiffCallback
หากต้องการใช้ฟังก์ชันของชั้นเรียน DiffUtil
ให้ขยาย DiffUtil.ItemCallback
- เปิด
SleepNightAdapter.kt
- ด้านล่างคําจํากัดความชั้นเรียนแบบเต็มของ
SleepNightAdapter
โปรดสร้างชั้นเรียนระดับบนสุดใหม่ชื่อSleepNightDiffCallback
ที่ขยายDiffUtil.ItemCallback
ส่งSleepNight
เป็นพารามิเตอร์ทั่วไป
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
- วางเคอร์เซอร์ในชื่อชั้นเรียน
SleepNightDiffCallback
- กด
Alt+Enter
(Option+Enter
ใน Mac) แล้วเลือกใช้สมาชิก - ในกล่องโต้ตอบที่เปิดขึ้น ให้กด Shift-คลิกซ้ายเพื่อเลือกเมธอด
areItemsTheSame()
และareContentsTheSame()
จากนั้นคลิกตกลง
การดําเนินการนี้จะสร้างตัวยึดตําแหน่งในSleepNightDiffCallback
สําหรับ 2 วิธีต่อไปนี้DiffUtil
จะใช้ 2 วิธีนี้เพื่อให้ทราบว่ารายการและลิสต์เปลี่ยนแปลงไปอย่างไร
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
- ภายใน
areItemsTheSame()
ให้แทนที่TODO
ด้วยรหัสที่ทดสอบว่าทั้งSleepNight
ที่ผ่านและผ่านมา,oldItem
และnewItem
เหมือนกันหรือไม่ หากสินค้ามีnightId
เหมือนกัน สินค้าจะเป็นสินค้าเดียวกัน ดังนั้นโปรดส่งคืนtrue
ไม่เช่นนั้น ให้คืนสินค้าfalse
DiffUtil
ใช้การทดสอบนี้เพื่อช่วยตรวจสอบว่ามีการเพิ่ม นําออก หรือย้ายรายการหรือไม่
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem.nightId == newItem.nightId
}
- ภายใน
areContentsTheSame()
ให้ตรวจสอบว่าoldItem
และnewItem
มีข้อมูลเดียวกันหรือไม่ ซึ่งก็คือความเท่ากัน การตรวจสอบความเท่าเทียมกันนี้จะตรวจสอบทุกช่อง เนื่องจากSleepNight
เป็นคลาสข้อมูลData
ชั้นเรียนจะกําหนดequals
และวิธีการอื่นๆ ให้คุณโดยอัตโนมัติ หากมีความแตกต่างระหว่างoldItem
และnewItem
โค้ดนี้จะแจ้งDiffUtil
ว่ารายการได้รับการอัปเดตแล้ว
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem == newItem
}
รูปแบบทั่วไปคือการใช้ RecyclerView
เพื่อแสดงรายการที่มีการเปลี่ยนแปลง RecyclerView
มีคลาสอะแดปเตอร์ ListAdapter
ที่ช่วยให้คุณสร้างอะแดปเตอร์ RecyclerView
ที่รายการรองรับได้
ListAdapter
จะติดตามรายการให้คุณและแจ้งเตือนอะแดปเตอร์เมื่ออัปเดตรายการ
ขั้นตอนที่ 1: เปลี่ยนอะแดปเตอร์เพื่อขยาย ListAdapter
- ในไฟล์
SleepNightAdapter.kt
ให้เปลี่ยนลายเซ็นของชั้นเรียนSleepNightAdapter
เพื่อขยายListAdapter
- หากมีข้อความแจ้ง ให้นําเข้า
androidx.recyclerview.widget.ListAdapter
- เพิ่ม
SleepNight
เป็นอาร์กิวเมนต์แรกในListAdapter
ก่อนSleepNightAdapter.ViewHolder
- เพิ่ม
SleepNightDiffCallback()
เป็นพารามิเตอร์ให้กับเครื่องมือสร้างListAdapter
จะใช้ค่านี้เพื่อดูสิ่งที่เปลี่ยนแปลงไปในรายการ ลายเซ็นของชั้นเรียนSleepNightAdapter
ที่เสร็จสิ้นแล้วควรจะมีลักษณะดังที่แสดงด้านล่าง
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
- ภายในช่อง
SleepNightAdapter
ให้ลบช่องdata
รวมถึงตัวตั้งค่าด้วย คุณไม่จําเป็นต้องใช้แล้ว เนื่องจากListAdapter
ติดตามรายการให้คุณ - ลบการลบล้าง
getItemCount()
เนื่องจากListAdapter
ใช้วิธีนี้ให้คุณ - หากต้องการกําจัดข้อผิดพลาดใน
onBindViewHolder()
ให้เปลี่ยนตัวแปรitem
แทนที่จะใช้data
ในการรับitem
โปรดเรียกใช้เมธอดgetItem(position)
ที่ListAdapter
val item = getItem(position)
ขั้นตอนที่ 2: ใช้ sendList() เพื่ออัปเดตรายการอยู่เสมอ
รหัสต้องแจ้ง ListAdapter
เมื่อมีรายการที่เปลี่ยนแปลง ListAdapter
ใช้วิธีการที่เรียกว่า submitList()
เพื่อแจ้ง ListAdapter
ว่ามีรายการเวอร์ชันใหม่ให้ใช้งาน เมื่อเรียกใช้เมธอดนี้ ListAdapter
จะแยกรายการใหม่กับข้อมูลเก่า และตรวจพบรายการที่เพิ่มเข้ามา นําออก ย้าย หรือเปลี่ยนแปลง จากนั้น ListAdapter
จะอัปเดตรายการที่แสดงโดย RecyclerView
- เปิด
SleepTrackerFragment.kt
- ใน
onCreateView()
ในการสังเกตการณ์บนsleepTrackerViewModel
ให้หาข้อผิดพลาดที่มีการอ้างอิงตัวแปรdata
ที่คุณได้ลบไว้ - แทนที่
adapter.data = it
ด้วยการเรียกadapter.submitList(it)
รหัสที่อัปเดตจะแสดงอยู่ด้านล่าง
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
- เรียกใช้แอป ทํางานได้เร็วขึ้น อาจสังเกตได้ยากหากรายการมีขนาดเล็ก
ในงานนี้ คุณใช้เทคนิคเดียวกับใน Codelab ก่อนหน้าเพื่อตั้งค่าการเชื่อมโยงข้อมูล และกําจัดการเรียกไปยัง findViewById()
ขั้นตอนที่ 1: เพิ่มการเชื่อมโยงข้อมูลไปยังไฟล์เลย์เอาต์
- เปิดไฟล์เลย์เอาต์
list_item_sleep_night.xml
ในแท็บ Text - วางเคอร์เซอร์ในแท็ก
ConstraintLayout
แล้วกดAlt+Enter
(Option+Enter
ใน Mac) เมนู Intent (เมนู "Quick Fix") จะเปิดขึ้น - เลือกแปลงเป็นเลย์เอาต์การเชื่อมโยงข้อมูล การดําเนินการนี้จะรวมเลย์เอาต์ไว้ใน
<layout>
และเพิ่มแท็ก<data>
ด้านใน - ที่ด้านบนสุด หากจําเป็น ให้ประกาศตัวแปรชื่อ
sleep
ภายในแท็ก<data>
- ตั้ง
type
เป็นชื่อที่ตรงตามเกณฑ์ทั้งหมดของSleepNight
ซึ่งก็คือcom.example.android.trackmysleepquality.database.SleepNight
แท็ก<data>
ที่สร้างเสร็จแล้วควรมีลักษณะดังที่แสดงด้านล่างนี้
<data>
<variable
name="sleep"
type="com.example.android.trackmysleepquality.database.SleepNight"/>
</data>
- หากต้องการบังคับให้สร้างออบเจ็กต์
Binding
ให้เลือก Build > Clean Project แล้วเลือก Build > Rebuild Project (หากยังพบปัญหาอยู่ ให้เลือก File > Validation Caches / Restart) ระบบจะเพิ่มออบเจ็กต์การเชื่อมโยงListItemSleepNightBinding
และโค้ดที่เกี่ยวข้องลงในไฟล์ที่สร้างของโปรเจ็กต์
ขั้นตอนที่ 2: จัดวางเลย์เอาต์สินค้าให้สูงเกินจริงโดยใช้การเชื่อมโยงข้อมูล
- เปิด
SleepNightAdapter.kt
- ค้นหาเมธอด
from()
ในคลาสViewHolder
- ลบการประกาศตัวแปร
view
โค้ดสําหรับลบ:
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
- เมื่อตัวแปร
view
อยู่ ให้กําหนดตัวแปรใหม่ชื่อbinding
ที่สูงเกินจริงออบเจ็กต์การเชื่อมโยงListItemSleepNightBinding
ดังที่แสดงด้านล่าง ทําการนําเข้าออบเจ็กต์การเชื่อมโยงที่จําเป็น
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
- ในตอนท้ายของฟังก์ชัน แทนที่จะส่งคืน
view
จะส่งคืนbinding
return ViewHolder(binding)
- วางเคอร์เซอร์บนคําว่า
binding
เพื่อกําจัดข้อผิดพลาด กดAlt+Enter
(Option+Enter
บน Mac) เพื่อเปิดเมนู Intent
- เลือกเปลี่ยนพารามิเตอร์ 'itemView' ประเภทตัวสร้างหลักของคลาส 'Viewholder' เป็น 'ListItemSleepNightBinding' การดําเนินการนี้จะอัปเดตประเภทพารามิเตอร์ของคลาส
ViewHolder
- เลื่อนขึ้นไปที่คําจํากัดความของคลาสของ
ViewHolder
เพื่อดูการเปลี่ยนแปลงในลายเซ็น คุณพบข้อผิดพลาดitemView
เนื่องจากได้เปลี่ยนitemView
เป็นbinding
ในเมธอดfrom()
ในคํานิยามของชั้นเรียนViewHolder
คลิกขวาที่หนึ่งในitemView
ที่มีอยู่ แล้วเลือก Rector > เปลี่ยนชื่อ เปลี่ยนชื่อเป็นbinding
- ใส่คํานําหน้าพารามิเตอร์
binding
ด้วยval
เป็นพร็อพเพอร์ตี้ - ในการโทรไปยังคลาสระดับบนสุด
RecyclerView.ViewHolder
ให้เปลี่ยนพารามิเตอร์จากbinding
เป็นbinding.root
คุณต้องส่งView
และbinding.root
เป็นรูทConstraintLayout
ในเลย์เอาต์ของรายการของคุณ - การประกาศชั้นเรียนที่เสร็จสิ้นแล้วควรจะเป็นโค้ดด้านล่าง
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){
คุณยังพบข้อผิดพลาดในการเรียกใช้ findViewById()
และจะแก้ไขในขั้นตอนต่อไป
ขั้นตอนที่ 3: แทนที่ FindViewById()
คุณสามารถอัปเดตพร็อพเพอร์ตี้ sleepLength
, quality
และ qualityImage
เพื่อใช้ออบเจ็กต์ binding
แทน findViewById()
ได้แล้ว
- เปลี่ยนการเริ่มต้นของ
sleepLength
,qualityString
และqualityImage
เพื่อใช้มุมมองของออบเจ็กต์binding
ดังที่แสดงด้านล่าง หลังจากนั้น โค้ดของคุณไม่ควรแสดงข้อผิดพลาดใดๆ
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage
เมื่อใช้ออบเจ็กต์การเชื่อมโยงแล้ว คุณไม่จําเป็นต้องกําหนดพร็อพเพอร์ตี้ sleepLength
, quality
และ qualityImage
อีกต่อไป DataBinding
จะแคชการค้นหา จึงไม่จําเป็นต้องประกาศพร็อพเพอร์ตี้เหล่านี้
- คลิกขวาที่ชื่อพร็อพเพอร์ตี้
sleepLength
,quality
และqualityImage
เลือก Rector > Inline หรือกดControl+Command+N
(Option+Command+N
บน Mac) - เรียกใช้แอป (คุณอาจต้องล้างและสร้างโปรเจ็กต์อีกครั้งหากมีข้อผิดพลาด)
ในงานนี้ คุณจะได้อัปเกรดแอปเพื่อใช้การเชื่อมโยงข้อมูลกับอะแดปเตอร์การเชื่อมโยงเพื่อตั้งค่าข้อมูลในมุมมอง
ใน Codelab ก่อนหน้า คุณใช้คลาส Transformations
เพื่อรับ LiveData
และสร้างสตริงที่จัดรูปแบบเพื่อแสดงในมุมมองข้อความ แต่หากต้องการเชื่อมโยงประเภทอื่นๆ หรือประเภทที่ซับซ้อน คุณสามารถใช้อะแดปเตอร์การเชื่อมโยงเพื่อช่วยให้การเชื่อมโยงข้อมูลใช้ประเภทดังกล่าวได้ อะแดปเตอร์สําหรับเชื่อมโยงคืออะแดปเตอร์ที่นําข้อมูลของคุณไปปรับให้เข้ากับสิ่งที่การเชื่อมโยงข้อมูลสามารถใช้เพื่อเชื่อมโยงข้อมูลพร็อพเพอร์ตี้ เช่น ข้อความหรือรูปภาพ
โดยคุณจะใช้อะแดปเตอร์ที่เชื่อมโยง 3 แบบ แบบหนึ่งสําหรับรูปภาพที่มีคุณภาพ และอีกแบบสําหรับช่องข้อความแต่ละช่อง โดยสรุป หากต้องการประกาศอะแดปเตอร์การเชื่อมโยง ให้กําหนดวิธีที่ใช้รายการและมุมมอง และใส่คําอธิบายประกอบด้วย @BindingAdapter
ในเนื้อหาของเมธอด คุณจะใช้วิธีการเปลี่ยนรูปแบบนี้ ใน Kotlin คุณเขียนอะแดปเตอร์การเชื่อมโยงเป็นฟังก์ชันส่วนขยายในระดับข้อมูลพร็อพเพอร์ตี้ที่ได้รับข้อมูลได้
ขั้นตอนที่ 1: สร้างอะแดปเตอร์การเชื่อมโยง
โปรดทราบว่าคุณจะต้องนําเข้าชั้นเรียนจํานวนหนึ่งในขั้นตอนดังกล่าว และระบบจะไม่เรียกใช้ทีละชั้นเรียน
- เปิด
SleepNightAdapater.kt
- ภายในคลาส
ViewHolder
ให้ค้นหาเมธอดbind()
และเตือนตัวเองว่าวิธีนี้ใช้ทําอะไร คุณจะได้นําโค้ดที่คํานวณค่าสําหรับbinding.sleepLength
,binding.quality
และbinding.qualityImage
แล้วใช้ภายในอะแดปเตอร์แทน (สําหรับตอนนี้ ให้ปล่อยโค้ดไว้ตามเดิมเพราะคุณย้ายโค้ดไปในภายหลัง) - ในแพ็กเกจ
sleeptracker
ให้สร้างและเปิดไฟล์ชื่อBindingUtils.kt
- ประกาศฟังก์ชันส่วนขยายใน
TextView
ชื่อsetSleepDurationFormatted
และส่งในSleepNight
ฟังก์ชันนี้จะเป็นอะแดปเตอร์สําหรับคํานวณและจัดรูปแบบระยะเวลาการนอนหลับ
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
- ในเนื้อหาของ
setSleepDurationFormatted
ให้เชื่อมโยงข้อมูลกับข้อมูลพร็อพเพอร์ตี้เช่นเดียวกับในViewHolder.bind()
เรียกconvertDurationToFormatted()
แล้วตั้งค่าtext
ของTextView
ให้เป็นข้อความที่จัดรูปแบบ (เนื่องจากนี่เป็นฟังก์ชันส่วนขยายในTextView
คุณจึงเข้าถึงพร็อพเพอร์ตี้text
ได้โดยตรง)
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
- หากต้องการแจ้งการเชื่อมโยงข้อมูลเกี่ยวกับอะแดปเตอร์การเชื่อมโยงนี้ ให้ใส่คําอธิบายประกอบ
@BindingAdapter
ลงในฟังก์ชัน - ฟังก์ชันนี้คืออะแดปเตอร์สําหรับแอตทริบิวต์
sleepDurationFormatted
ดังนั้นโปรดส่งsleepDurationFormatted
เป็นอาร์กิวเมนต์ใน@BindingAdapter
@BindingAdapter("sleepDurationFormatted")
- อะแดปเตอร์ที่ 2 จะกําหนดคุณภาพการนอนหลับโดยอิงตามค่าในออบเจ็กต์
SleepNight
สร้างฟังก์ชันส่วนขยายชื่อsetSleepQualityString()
ในTextView
แล้วส่งในSleepNight
- เชื่อมโยงข้อมูลกับข้อมูลพร็อพเพอร์ตี้เช่นเดียวกับใน
ViewHolder.bind()
โทรconvertNumericQualityToString
และตั้งค่าtext
- เพิ่มคําอธิบายประกอบให้กับฟังก์ชันด้วย
@BindingAdapter("sleepQualityString")
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
- อะแดปเตอร์การเชื่อมโยงที่ 3 จะตั้งค่ารูปภาพในมุมมองรูปภาพ สร้างฟังก์ชันส่วนขยายใน
ImageView
โทรหาsetSleepImage
และใช้รหัสจากViewHolder.bind()
ดังที่แสดงด้านล่าง
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
setImageResource(when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
})
}
ขั้นตอนที่ 2: อัปเดต SleepNightAdapter
- เปิด
SleepNightAdapter.kt
- ลบทุกอย่างในเมธอด
bind()
เพราะตอนนี้คุณใช้การเชื่อมโยงข้อมูลและอะแดปเตอร์ใหม่เพื่อการดําเนินการนี้ให้คุณได้
fun bind(item: SleepNight) {
}
- ให้สิทธิ์
bind()
ภายในitem
เพราะคุณต้องแจ้งออบเจ็กต์การเชื่อมโยงเกี่ยวกับSleepNight
ใหม่
binding.sleep = item
- เพิ่ม
binding.executePendingBindings()
ด้านล่างบรรทัดนั้น การเรียกนี้เป็นการเพิ่มประสิทธิภาพที่ขอให้เชื่อมโยงข้อมูลเพื่อเรียกใช้การเชื่อมโยงที่รอดําเนินการทันที การเรียกใช้executePendingBindings()
เสมอเมื่อใช้อะแดปเตอร์การเชื่อมโยงในRecyclerView
เป็นความคิดที่ดี เนื่องจากสามารถปรับขนาดมุมมองได้เล็กน้อย
binding.executePendingBindings()
ขั้นตอนที่ 3: เพิ่มการเชื่อมโยงลงในเลย์เอาต์ XML
- เปิด
list_item_sleep_night.xml
- ใน
ImageView
ให้เพิ่มพร็อพเพอร์ตี้app
ที่มีชื่อเดียวกันกับอะแดปเตอร์การเชื่อมโยงที่ตั้งค่ารูปภาพ ส่งผ่านตัวแปรsleep
ดังที่แสดงด้านล่าง
พร็อพเพอร์ตี้นี้จะสร้างการเชื่อมต่อระหว่างข้อมูลพร็อพเพอร์ตี้และออบเจ็กต์การเชื่อมโยงผ่านอะแดปเตอร์ เมื่อใดก็ตามที่มีการอ้างอิงsleepImage
อะแดปเตอร์จะปรับข้อมูลจากSleepNight
app:sleepImage="@{sleep}"
- ทําแบบเดียวกันนี้สําหรับมุมมองข้อความ
sleep_length
และquality_string
เมื่อใดก็ตามที่มีการอ้างอิงsleepDurationFormatted
หรือsleepQualityString
อะแดปเตอร์จะปรับข้อมูลจากSleepNight
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
- เรียกใช้แอป และทํางานเหมือนที่เคยทําก่อนหน้านี้ อะแดปเตอร์การเชื่อมโยงจะดูแลงานการจัดรูปแบบและการอัปเดตมุมมองทั้งหมดขณะข้อมูลมีการเปลี่ยนแปลง การปรับให้
ViewHolder
ง่ายขึ้น และให้โครงสร้างโค้ดที่ดีกว่าเดิมมาก
คุณแสดงรายการของแบบฝึกหัดล่าสุด 2-3 รายการ ซึ่งได้รับการออกแบบให้แสดงให้เห็นว่าอินเทอร์เฟซ Adapter
ช่วยให้คุณสถาปัตยกรรมโค้ดได้หลายวิธี โค้ดยิ่งมีความซับซ้อนมากเท่าไร ยิ่งต้องออกแบบสถาปัตยกรรมก็ยิ่งดีเท่านั้น ในแอปเวอร์ชันที่ใช้งานจริง รูปแบบเหล่านี้และอื่นๆ จะใช้กับ RecyclerView
รูปแบบทั้งหมดต่างก็ใช้ได้ผล และแต่ละรูปแบบต่างก็มีประโยชน์ การเลือกได้ว่าจะสร้างแบบใดนั้นขึ้นอยู่กับสิ่งที่คุณสร้าง
ยินดีด้วย ตอนนี้คุณกําลังจะได้ฝึกหัด RecyclerView
บน Android อย่างเชี่ยวชาญแล้ว
โปรเจ็กต์ Android Studio: RecyclerViewDiffUtilDataBinding
DiffUtil
:
RecyclerView
มีคลาสชื่อDiffUtil
ซึ่งมีไว้สําหรับการคํานวณความแตกต่างระหว่าง 2 รายการDiffUtil
มีคลาสชื่อว่าItemCallBack
ที่คุณขยายเพื่อดูความแตกต่างระหว่าง 2 รายการ- ในชั้นเรียน
ItemCallback
คุณต้องลบล้างเมธอดareItemsTheSame()
และareContentsTheSame()
ListAdapter
:
- หากต้องการผู้จัดการบางรายการฟรี คุณสามารถใช้ชั้นเรียน
ListAdapter
แทนRecyclerView.Adapter
อย่างไรก็ตาม หากใช้ListAdapter
คุณต้องเขียนอะแดปเตอร์สําหรับเลย์เอาต์อื่นๆ โดยเฉพาะ ซึ่งเป็นเหตุผลที่ Codelab นี้จะแสดงวิธีดําเนินการดังกล่าว - หากต้องการเปิดเมนู Intent ใน Android Studio ให้วางเคอร์เซอร์บนรายการโค้ดใดก็ได้ แล้วกด
Alt+Enter
(Option+Enter
บน Mac) เมนูนี้มีประโยชน์อย่างยิ่งสําหรับการรีแฟคเตอร์โค้ดและสร้างต้นขั้วสําหรับวิธีการต่างๆ เมนูนี้คํานึงถึงบริบท ดังนั้น คุณจึงต้องวางเคอร์เซอร์ตรงเพื่อรับเมนูที่ถูกต้อง
การเชื่อมโยงข้อมูล:
- ใช้การเชื่อมโยงข้อมูลในเลย์เอาต์รายการเพื่อเชื่อมโยงข้อมูลกับข้อมูลพร็อพเพอร์ตี้
อะแดปเตอร์การเชื่อมโยง:
- ก่อนหน้านี้คุณใช้
Transformations
เพื่อสร้างสตริงจากข้อมูล หากต้องการเชื่อมโยงข้อมูลประเภทต่างๆ หรือที่ซับซ้อน ให้ระบุอะแดปเตอร์การเชื่อมโยงเพื่อช่วยให้เชื่อมโยงข้อมูลได้ - หากต้องการประกาศอะแดปเตอร์การเชื่อมโยง ให้กําหนดวิธีที่ใช้รายการและมุมมอง รวมถึงใส่คําอธิบายประกอบเมธอดด้วย
@BindingAdapter
ใน Kotlin คุณเขียนอะแดปเตอร์การเชื่อมโยงเป็นฟังก์ชันส่วนขยายในView
ได้ ส่งชื่อของพร็อพเพอร์ตี้ที่อะแดปเตอร์จะปรับ เช่น
@BindingAdapter("sleepDurationFormatted")
- ในเลย์เอาต์ XML ให้ตั้งค่าพร็อพเพอร์ตี้
app
โดยใช้ชื่อเดียวกับอะแดปเตอร์การเชื่อมโยง ส่งตัวแปรด้วยข้อมูล เช่น
.app:sleepDurationFormatted="@{sleep}"
หลักสูตร Udacity:
เอกสารประกอบสําหรับนักพัฒนาซอฟต์แวร์ Android
- สร้างรายการด้วย RecyclerView
RecyclerView
DiffUtil
- ไลบรารีการเชื่อมโยงข้อมูล
- การเชื่อมโยงอะแดปเตอร์
notifyDataSetChanged()
Transformations
แหล่งข้อมูลอื่นๆ
ส่วนนี้จะอธิบายการบ้านและรายงานสําหรับนักเรียนที่ทํางานผ่าน Codelab นี้ซึ่งเป็นส่วนหนึ่งของหลักสูตรที่นําโดยผู้สอน สิ่งที่ผู้สอนต้องทํามีดังนี้
- มอบหมายการบ้านหากจําเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานทําการบ้าน
- ตัดเกรดการบ้าน
ผู้สอนจะใช้คําแนะนําเหล่านี้เท่าใดก็ได้หรือตามที่ต้องการก็ได้ และสามารถกําหนดให้การบ้านอื่นๆ ที่ตนคิดว่าเหมาะสมได้
หากคุณใช้ Codelab ด้วยตัวเอง ก็ให้ใช้การบ้านเพื่อทดสอบความรู้ของคุณได้
ตอบคําถามเหล่านี้
คำถามที่ 1
ข้อใดต่อไปนี้จําเป็นในการใช้ DiffUtil
เลือกได้มากกว่า 1 ข้อ
▢ ขยายคลาส ItemCallBack
▢ ลบล้าง areItemsTheSame()
▢ ลบล้าง areContentsTheSame()
▢ ใช้การเชื่อมโยงข้อมูลเพื่อติดตามความแตกต่างระหว่างรายการต่างๆ
คําถามที่ 2 2
ข้อใดต่อไปนี้เป็นจริงเกี่ยวกับอะแดปเตอร์การเชื่อมโยง
▢ อะแดปเตอร์การเชื่อมโยงคือฟังก์ชันที่มีคําอธิบายประกอบกับ @BindingAdapter
▢ การใช้อะแดปเตอร์การเชื่อมโยงช่วยให้คุณแยกการจัดรูปแบบข้อมูลออกจากผู้ถือมุมมองได้
▢ คุณจะต้องใช้ RecyclerViewAdapter
หากต้องการใช้อะแดปเตอร์สําหรับการเชื่อมโยง
▢ การเชื่อมโยงอะแดปเตอร์ เป็นคําตอบที่ดีเมื่อคุณต้องการเปลี่ยนรูปแบบข้อมูลที่ซับซ้อน
คําถาม 3
คุณควรพิจารณาใช้ Transformations
แทนอะแดปเตอร์การเชื่อมโยงเมื่อใด เลือกได้มากกว่า 1 ข้อ
▢ ข้อมูลของคุณเป็นเรื่องง่าย
▢ คุณกําลังจัดรูปแบบสตริง
▢ รายการของคุณยาวมาก
▢ ViewHolder
ของคุณมีมุมมองเพียงครั้งเดียว
เริ่มบทเรียนถัดไป: