Codelab นี้เป็นส่วนหนึ่งของหลักสูตรหลักพื้นฐานของ Android Kotlin คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้หากทำตาม Codelab ตามลำดับ Codelab ของหลักสูตรทั้งหมดแสดงอยู่ในหน้า Landing Page ของ Codelab หลักพื้นฐานของ Android Kotlin
บทนำ
Codelab นี้จะสอนวิธีใช้ RecyclerView เพื่อแสดงรายการสินค้า จากแอปติดตามการนอนหลับใน Codelab ชุดก่อนหน้า คุณจะได้เรียนรู้วิธีแสดงข้อมูลที่ดีและหลากหลายมากขึ้นโดยใช้ RecyclerView ที่มีสถาปัตยกรรมที่แนะนำ
สิ่งที่คุณควรทราบอยู่แล้ว
คุณควรคุ้นเคยกับสิ่งต่อไปนี้
- การสร้างอินเทอร์เฟซผู้ใช้ (UI) พื้นฐานโดยใช้กิจกรรม Fragment และมุมมอง
- การไปยังส่วนย่อยต่างๆ และการใช้
safeArgsเพื่อส่งข้อมูลระหว่างส่วนย่อย - การใช้ View Model, View Model Factory, Transformation และ
LiveDataรวมถึง Observer ขององค์ประกอบเหล่านั้น - การสร้างฐานข้อมูล
Roomการสร้าง DAO และการกําหนดเอนทิตี - การใช้โครูทีนสำหรับงานฐานข้อมูลและงานอื่นๆ ที่ใช้เวลานาน
สิ่งที่คุณจะได้เรียนรู้
- วิธีใช้
RecyclerViewกับAdapterและViewHolderเพื่อแสดงรายการสินค้า
สิ่งที่คุณต้องดำเนินการ
- เปลี่ยนแอป TrackMySleepQuality จากบทเรียนก่อนหน้าให้ใช้
RecyclerViewเพื่อแสดงข้อมูลคุณภาพการนอนหลับ
ใน Codelab นี้ คุณจะได้สร้างRecyclerViewส่วนหนึ่งของแอปที่ติดตามคุณภาพการนอนหลับ แอปใช้ฐานข้อมูล Room เพื่อจัดเก็บข้อมูลการนอนหลับเมื่อเวลาผ่านไป
แอปติดตามการนอนหลับเริ่มต้นมี 2 หน้าจอซึ่งแสดงด้วย Fragment ดังที่แสดงในรูปภาพด้านล่าง

หน้าจอแรกที่แสดงทางด้านซ้ายมีปุ่มสำหรับเริ่มและหยุดการติดตาม หน้าจอนี้ยังแสดงข้อมูลการนอนหลับทั้งหมดของผู้ใช้ด้วย ปุ่มล้างจะลบข้อมูลทั้งหมดที่แอปเก็บรวบรวมไว้สำหรับผู้ใช้ออกอย่างถาวร หน้าจอที่ 2 ซึ่งแสดงทางด้านขวาใช้สำหรับเลือกคะแนนคุณภาพการนอนหลับ
แอปนี้ใช้สถาปัตยกรรมที่เรียบง่ายพร้อมตัวควบคุม UI, ViewModel และ LiveData นอกจากนี้ แอปยังใช้Roomฐานข้อมูลเพื่อให้ข้อมูลการนอนหลับคงอยู่ถาวร

รายการคืนที่นอนหลับที่แสดงในหน้าจอแรกใช้งานได้ แต่ไม่สวยงาม แอปใช้ตัวจัดรูปแบบที่ซับซ้อนเพื่อสร้างสตริงข้อความสำหรับมุมมองข้อความและตัวเลขสำหรับคุณภาพ นอกจากนี้ การออกแบบนี้ยังไม่สามารถปรับขนาดได้ หลังจากแก้ไขปัญหาทั้งหมดในโค้ดแล็บนี้แล้ว แอปสุดท้ายจะมีฟังก์ชันการทำงานเหมือนเดิม และหน้าจอหลักจะมีลักษณะดังนี้

การแสดงรายการหรือตารางกริดของข้อมูลเป็นหนึ่งในงาน UI ที่พบบ่อยที่สุดใน Android รายการอาจมีตั้งแต่แบบง่ายไปจนถึงซับซ้อนมาก รายการมุมมองข้อความอาจแสดงข้อมูลอย่างง่าย เช่น รายการช็อปปิ้ง รายการที่ซับซ้อน เช่น รายการสถานที่ท่องเที่ยวที่มีคำอธิบายประกอบ อาจแสดงรายละเอียดมากมายแก่ผู้ใช้ภายในตารางแบบเลื่อนที่มีส่วนหัว
Android มีRecyclerViewวิดเจ็ตเพื่อรองรับกรณีการใช้งานทั้งหมดนี้

ประโยชน์ที่ยิ่งใหญ่ที่สุดของ RecyclerView คือการทำงานกับรายการขนาดใหญ่ได้อย่างมีประสิทธิภาพ
- โดยค่าเริ่มต้น
RecyclerViewจะประมวลผลหรือวาดเฉพาะรายการที่มองเห็นได้บนหน้าจอในขณะนั้น เช่น หากลิสต์มีองค์ประกอบ 1,000 รายการ แต่มีเพียง 10 รายการที่มองเห็นได้RecyclerViewจะทำงานเพียงพอที่จะวาด 10 รายการบนหน้าจอเท่านั้น เมื่อผู้ใช้เลื่อนRecyclerViewจะพิจารณาว่าควรมีสินค้าใหม่ใดบนหน้าจอ และทำงานเพียงพอที่จะแสดงสินค้าเหล่านั้น - เมื่อรายการเลื่อนออกจากหน้าจอ ระบบจะนำมุมมองของรายการนั้นกลับมาใช้ใหม่ ซึ่งหมายความว่ารายการนั้นจะเต็มไปด้วยเนื้อหาใหม่ที่เลื่อนเข้ามาในหน้าจอ ลักษณะการทำงานของ
RecyclerViewนี้ช่วยประหยัดเวลาในการประมวลผลได้มากและช่วยให้รายการเลื่อนได้อย่างราบรื่น - เมื่อรายการมีการเปลี่ยนแปลง
RecyclerViewจะอัปเดตเฉพาะรายการนั้นแทนที่จะวาดทั้งลิสต์ใหม่ ซึ่งจะช่วยเพิ่มประสิทธิภาพได้อย่างมากเมื่อแสดงรายการที่ซับซ้อน
ในลําดับที่แสดงด้านล่าง คุณจะเห็นว่ามุมมองหนึ่งมีข้อมูลอยู่ ABC หลังจากที่มุมมองนั้นเลื่อนออกจากหน้าจอแล้ว RecyclerView จะนำมุมมองนั้นกลับมาใช้ซ้ำกับข้อมูลใหม่ XYZ
รูปแบบอะแดปเตอร์
หากเคยเดินทางระหว่างประเทศที่ใช้เต้ารับไฟฟ้าต่างกัน คุณอาจทราบวิธีเสียบอุปกรณ์เข้ากับเต้ารับโดยใช้อะแดปเตอร์ อะแดปเตอร์ช่วยให้คุณแปลงปลั๊กประเภทหนึ่งเป็นอีกประเภทหนึ่ง ซึ่งก็คือการแปลงอินเทอร์เฟซหนึ่งเป็นอีกอินเทอร์เฟซหนึ่ง
รูปแบบอะแดปเตอร์ในวิศวกรรมซอฟต์แวร์ช่วยให้ออบเจ็กต์ทำงานร่วมกับ API อื่นได้ RecyclerView ใช้อะแดปเตอร์เพื่อแปลงข้อมูลแอปเป็นสิ่งที่ RecyclerView แสดงได้ โดยไม่เปลี่ยนวิธีที่แอปจัดเก็บและประมวลผลข้อมูล สำหรับแอปติดตามการนอนหลับ คุณจะสร้างอแดปเตอร์ที่แปลงข้อมูลจากRoomฐานข้อมูลเป็นรูปแบบที่ RecyclerView รู้ว่าจะแสดงอย่างไรโดยไม่ต้องเปลี่ยนViewModel
การใช้งาน RecyclerView

หากต้องการแสดงข้อมูลใน RecyclerView คุณต้องมีส่วนต่อไปนี้
- ข้อมูลที่จะแสดง
- อินสแตนซ์
RecyclerViewที่กำหนดไว้ในไฟล์เลย์เอาต์เพื่อทำหน้าที่เป็นคอนเทนเนอร์สำหรับมุมมอง - เลย์เอาต์สำหรับข้อมูล 1 รายการ
หากรายการทั้งหมดในลิสต์มีลักษณะเหมือนกัน คุณสามารถใช้เลย์เอาต์เดียวกันสำหรับรายการทั้งหมดได้ แต่ไม่จำเป็นต้องทำ ต้องสร้างเลย์เอาต์ของรายการแยกจากเลย์เอาต์ของ Fragment เพื่อให้สร้างและป้อนข้อมูลในมุมมองรายการได้ครั้งละ 1 รายการ - เครื่องมือจัดการเลย์เอาต์
เครื่องมือจัดการเลย์เอาต์จะจัดการการจัดระเบียบ (เลย์เอาต์) ของคอมโพเนนต์ UI ในมุมมอง - ตัวยึดมุมมอง
ตัวยึดมุมมองขยายคลาสViewHolderซึ่งมีข้อมูลมุมมองสําหรับแสดงรายการเดียวจากเลย์เอาต์ของรายการ นอกจากนี้ ตัวยึดมุมมองยังเพิ่มข้อมูลที่RecyclerViewใช้เพื่อย้ายมุมมองไปรอบๆ หน้าจอได้อย่างมีประสิทธิภาพ - อะแดปเตอร์
อะแดปเตอร์จะเชื่อมต่อข้อมูลกับRecyclerViewโดยจะปรับข้อมูลเพื่อให้แสดงในViewHolderได้RecyclerViewใช้ตัวดัดแปลงเพื่อดูวิธีแสดงข้อมูลบนหน้าจอ
ในงานนี้ คุณจะได้เพิ่ม RecyclerView ลงในไฟล์เลย์เอาต์และตั้งค่า Adapter เพื่อแสดงข้อมูลการนอนหลับต่อ RecyclerView
ขั้นตอนที่ 1: เพิ่ม RecyclerView ด้วย LayoutManager
ในขั้นตอนนี้ คุณจะแทนที่ ScrollView ด้วย RecyclerView ในไฟล์ fragment_sleep_tracker.xml
- ดาวน์โหลดแอป RecyclerViewFundamentals-Starter จาก GitHub
- สร้างและเรียกใช้แอป สังเกตวิธีแสดงข้อมูลเป็นข้อความธรรมดา
- เปิด
fragment_sleep_tracker.xmlไฟล์เลย์เอาต์ในแท็บออกแบบใน Android Studio - ในบานหน้าต่างแผนผังคอมโพเนนต์ ให้ลบ
ScrollViewการดำเนินการนี้จะลบTextViewที่อยู่ภายในScrollViewด้วย - ในแผงจานสี ให้เลื่อนดูรายการประเภทคอมโพเนนต์ทางด้านซ้ายเพื่อค้นหาคอนเทนเนอร์ แล้วเลือก
- ลาก
RecyclerViewจากบานหน้าต่างจานสีไปยังบานหน้าต่างแผนผังคอมโพเนนต์ วางRecyclerViewไว้ในConstraintLayout

- หากมีกล่องโต้ตอบเปิดขึ้นมาถามว่าต้องการเพิ่มทรัพยากร Dependency หรือไม่ ให้คลิกตกลงเพื่อให้ Android Studio เพิ่มทรัพยากร Dependency
recyclerviewลงในไฟล์ Gradle ซึ่งอาจใช้เวลา 2-3 วินาที จากนั้นแอปจะซิงค์

- เปิดไฟล์โมดูล
build.gradleเลื่อนไปที่ด้านล่างสุด และจดบันทึกทรัพยากร Dependency ใหม่ซึ่งมีลักษณะคล้ายกับโค้ดด้านล่าง
implementation 'androidx.recyclerview:recyclerview:1.0.0'
- เปลี่ยนกลับเป็น
fragment_sleep_tracker.xml - ในแท็บข้อความ ให้มองหาโค้ด
RecyclerViewที่แสดงด้านล่าง
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent" />- ให้
RecyclerViewidจากsleep_list
android:id="@+id/sleep_list"- วาง
RecyclerViewให้ครอบคลุมส่วนที่เหลือของหน้าจอภายในConstraintLayoutโดยจำกัดด้านบนของRecyclerViewกับปุ่มเริ่ม ด้านล่างกับปุ่มล้าง และแต่ละด้านกับองค์ประกอบหลัก ตั้งค่าความกว้างและความสูงของเลย์เอาต์เป็น 0 dp ในเครื่องมือแก้ไขเลย์เอาต์หรือใน XML โดยใช้โค้ดต่อไปนี้
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/clear_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/stop_button"- เพิ่ม Layout Manager ลงใน
RecyclerViewXML ทุกRecyclerViewต้องมี Layout Manager ที่บอกวิธีจัดตำแหน่งรายการในลิสต์ Android มีLinearLayoutManagerซึ่งโดยค่าเริ่มต้นจะจัดวางรายการในรายการแนวตั้งของแถวที่มีความกว้างเต็ม
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"- สลับไปที่แท็บออกแบบ แล้วสังเกตว่าข้อจำกัดที่เพิ่มเข้ามาทำให้
RecyclerViewขยายออกเพื่อเติมพื้นที่ว่าง

ขั้นตอนที่ 2: สร้างเลย์เอาต์รายการและตัวยึดมุมมองข้อความ
RecyclerView เป็นเพียงคอนเทนเนอร์เท่านั้น ในขั้นตอนนี้ คุณจะได้สร้างเลย์เอาต์และโครงสร้างพื้นฐานสำหรับรายการที่จะแสดงภายใน RecyclerView
หากต้องการให้ RecyclerView ทำงานได้โดยเร็วที่สุด ในตอนแรกคุณจะใช้รายการที่เรียบง่ายซึ่งแสดงเฉพาะคุณภาพการนอนหลับเป็นตัวเลข โดยคุณต้องมีตัวยึดมุมมอง TextItemViewHolder นอกจากนี้ คุณยังต้องมีมุมมอง ซึ่งก็คือ TextView สำหรับข้อมูลด้วย (ในขั้นตอนถัดไป คุณจะได้ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวยึดมุมมองและวิธีจัดวางข้อมูลการนอนหลับทั้งหมด)
- สร้างไฟล์เลย์เอาต์ชื่อ
text_item_view.xmlไม่ว่าคุณจะใช้อะไรเป็นองค์ประกอบรากก็ไม่สำคัญ เนื่องจากคุณจะแทนที่โค้ดเทมเพลต - ใน
text_item_view.xmlให้ลบรหัสทั้งหมดที่ระบุ - เพิ่ม
TextViewโดยมีระยะห่างภายใน16dpที่จุดเริ่มต้นและจุดสิ้นสุด และขนาดข้อความ24spกำหนดให้ความกว้างตรงกับองค์ประกอบระดับบนสุด และความสูงครอบคลุมเนื้อหา เนื่องจากมุมมองนี้แสดงภายในRecyclerViewคุณจึงไม่จำเป็นต้องวางมุมมองภายในViewGroup
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:textSize="24sp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />- เปิด
Util.ktเลื่อนไปที่ท้ายสุดแล้วเพิ่มคำจำกัดความที่แสดงด้านล่าง ซึ่งจะสร้างTextItemViewHolderคลาส วางโค้ดไว้ที่ด้านล่างของไฟล์ หลังเครื่องหมายปีกกาปิดตัวสุดท้าย โค้ดจะอยู่ในUtil.ktเนื่องจากตัวยึดมุมมองนี้เป็นแบบชั่วคราวและคุณจะแทนที่ในภายหลัง
class TextItemViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView)- หากได้รับข้อความแจ้ง ให้นำเข้า
android.widget.TextViewและandroidx.recyclerview.widget.RecyclerView
ขั้นตอนที่ 3: สร้าง SleepNightAdapter
งานหลักในการติดตั้งใช้งาน RecyclerView คือการสร้างอแดปเตอร์ คุณมีตัวยึดมุมมองที่เรียบง่ายสำหรับมุมมองรายการ และเลย์เอาต์สำหรับแต่ละรายการ ตอนนี้คุณสร้างอะแดปเตอร์ได้แล้ว อแดปเตอร์จะสร้างตัวยึดมุมมองและป้อนข้อมูลลงในตัวยึดมุมมองเพื่อให้ RecyclerView แสดง
- ใน
sleeptrackerแพ็กเกจ ให้สร้างคลาส Kotlin ใหม่ชื่อSleepNightAdapter - ทำให้คลาส
SleepNightAdapterขยายRecyclerView.Adapterคลาสนี้ชื่อSleepNightAdapterเนื่องจากจะแปลงออบเจ็กต์SleepNightให้เป็นสิ่งที่RecyclerViewใช้ได้ อะแดปเตอร์ต้องทราบว่าจะใช้ตัวยึดมุมมองใด จึงต้องส่งTextItemViewHolderเข้ามา นำเข้าคอมโพเนนต์ที่จำเป็นเมื่อได้รับแจ้ง จากนั้นคุณจะเห็นข้อผิดพลาดเนื่องจากมีเมธอดที่ต้องใช้ในการติดตั้งใช้งาน
class SleepNightAdapter: RecyclerView.Adapter<TextItemViewHolder>() {}- ที่ระดับบนสุดของ
SleepNightAdapterให้สร้างตัวแปรlistOfSleepNightเพื่อเก็บข้อมูล
var data = listOf<SleepNight>()- ใน
SleepNightAdapterให้ลบล้างgetItemCount()เพื่อแสดงขนาดของรายการคืนที่นอนหลับในdataRecyclerViewต้องทราบจำนวนรายการที่อะแดปเตอร์มีเพื่อแสดง และจะทำได้โดยการเรียกใช้getItemCount()
override fun getItemCount() = data.size- ใน
SleepNightAdapterให้ลบล้างฟังก์ชันonBindViewHolder()ดังที่แสดงด้านล่างRecyclerViewจะเรียกใช้ฟังก์ชันonBindViewHolder()เพื่อแสดงข้อมูลสำหรับรายการในลิสต์ 1 รายการที่ตำแหน่งที่ระบุ ดังนั้นเมธอดonBindViewHolder()จึงรับอาร์กิวเมนต์ 2 รายการ ได้แก่ ตัวยึดมุมมองและตำแหน่งของข้อมูลที่จะเชื่อมโยง สำหรับแอปนี้ ตัวยึดตำแหน่งคือTextItemViewHolderและตำแหน่งคือตำแหน่งในรายการ
override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
}- สร้างตัวแปรสำหรับรายการหนึ่งๆ ในตำแหน่งที่กำหนดในข้อมูลภายใน
onBindViewHolder()
val item = data[position]ViewHolderที่คุณสร้างมีพร็อพเพอร์ตี้ชื่อtextViewภายในonBindViewHolder()ให้ตั้งค่าtextของtextViewเป็นหมายเลขคุณภาพการนอนหลับ โค้ดนี้จะแสดงเฉพาะรายการตัวเลข แต่ตัวอย่างง่ายๆ นี้จะช่วยให้คุณเห็นว่าอแดปเตอร์นำข้อมูลไปยังตัวยึดมุมมองและไปยังหน้าจอได้อย่างไร
holder.textView.text = item.sleepQuality.toString()- ใน
SleepNightAdapterให้ลบล้างและใช้onCreateViewHolder()ซึ่งจะเรียกใช้เมื่อRecyclerViewต้องการตัวยึดมุมมองเพื่อแสดงรายการ
ฟังก์ชันนี้ใช้พารามิเตอร์ 2 รายการและส่งคืนViewHolderพารามิเตอร์parentซึ่งเป็นกลุ่มมุมมองที่เก็บตัวยึดมุมมองจะเป็นRecyclerViewเสมอ ระบบจะใช้พารามิเตอร์viewTypeเมื่อมีหลายมุมมองในRecyclerViewเดียวกัน เช่น หากคุณใส่รายการมุมมองข้อความ รูปภาพ และวิดีโอทั้งหมดในRecyclerViewเดียวกัน ฟังก์ชันonCreateViewHolder()จะต้องทราบประเภทมุมมองที่จะใช้
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
}- ใน
onCreateViewHolder()ให้สร้างอินสแตนซ์ของLayoutInflater
LayoutInflater รู้ว่าจะสร้าง View จากเลย์เอาต์ XML ได้อย่างไรcontextมีข้อมูลเกี่ยวกับวิธีขยายมุมมองอย่างถูกต้อง ในอแดปเตอร์สำหรับ RecyclerView คุณจะส่งบริบทของparentViewGroup เสมอ ซึ่งก็คือRecyclerView
val layoutInflater = LayoutInflater.from(parent.context)- ใน
onCreateViewHolder()ให้สร้างviewโดยขอให้layoutinflaterพองตัว
ส่งเลย์เอาต์ XML สำหรับมุมมอง และกลุ่มมุมมองparentสำหรับมุมมอง อาร์กิวเมนต์ที่ 3 ซึ่งเป็นบูลีนคือattachToRootอาร์กิวเมนต์นี้ต้องเป็นfalseเนื่องจากRecyclerViewจะเพิ่มรายการนี้ลงในลำดับชั้นของมุมมองให้คุณเมื่อถึงเวลา
val view = layoutInflater
.inflate(R.layout.text_item_view, parent, false) as TextView- ใน
onCreateViewHolder()ให้ส่งคืนTextItemViewHolderที่สร้างด้วยview
return TextItemViewHolder(view)- อแดปเตอร์ต้องแจ้งให้
RecyclerViewทราบเมื่อdataเปลี่ยนแปลง เนื่องจากRecyclerViewไม่ทราบข้อมูลใดๆRecyclerViewจะทราบเฉพาะตัวยึดมุมมองที่อแดปเตอร์ส่งให้เท่านั้น หากต้องการบอกRecyclerViewเมื่อข้อมูลที่แสดงมีการเปลี่ยนแปลง ให้เพิ่มตัวตั้งค่าที่กำหนดเองลงในตัวแปรdataที่อยู่ด้านบนของคลาสSleepNightAdapterในตัวตั้งค่า ให้กำหนดค่าใหม่ให้กับdataจากนั้นเรียกใช้notifyDataSetChanged()เพื่อทริกเกอร์การวาดรายการใหม่ด้วยข้อมูลใหม่
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
}ขั้นตอนที่ 4: บอก RecyclerView เกี่ยวกับ Adapter
RecyclerView ต้องทราบเกี่ยวกับอแดปเตอร์ที่จะใช้เพื่อรับตัวยึดมุมมอง
- เปิด
SleepTrackerFragment.kt - สร้างอะแดปเตอร์ใน
onCreateview()วางโค้ดนี้หลังการสร้างViewModelโมเดลViewModelและก่อนคำสั่งreturn
val adapter = SleepNightAdapter()- เชื่อมโยง
adapterกับRecyclerView
binding.sleepList.adapter = adapter- ล้างและสร้างโปรเจ็กต์ใหม่เพื่ออัปเดตออบเจ็กต์
binding
หากยังพบข้อผิดพลาดเกี่ยวกับbinding.sleepListหรือbinding.FragmentSleepTrackerBindingให้ล้างแคชและรีสตาร์ท (เลือกไฟล์ > ล้างแคช / รีสตาร์ท)
หากเรียกใช้แอปตอนนี้จะไม่มีข้อผิดพลาด แต่คุณจะไม่เห็นข้อมูลใดๆ แสดงเมื่อแตะเริ่ม แล้วแตะหยุด
ขั้นตอนที่ 5: รับข้อมูลลงในอแดปเตอร์
ตอนนี้คุณมีอะแดปเตอร์และวิธีรับข้อมูลจากอะแดปเตอร์ไปยัง RecyclerView แล้ว ตอนนี้คุณต้องนำข้อมูลจาก ViewModel ไปยังอแดปเตอร์
- เปิด
SleepTrackerViewModel - ค้นหาตัวแปร
nightsซึ่งจัดเก็บคืนที่นอนหลับทั้งหมด ซึ่งเป็นข้อมูลที่จะแสดง ระบบจะตั้งค่าตัวแปรnightsโดยการเรียกใช้getAllNights()ในฐานข้อมูล - นำ
privateออกจากnightsเนื่องจากคุณจะสร้าง Observer ที่ต้องเข้าถึงตัวแปรนี้ การประกาศควรมีลักษณะดังนี้
val nights = database.getAllNights()- เปิด
SleepDatabaseDaoในdatabaseแพ็กเกจ - ค้นหาฟังก์ชัน
getAllNights()โปรดทราบว่าฟังก์ชันนี้จะแสดงผลรายการค่าSleepNightเป็นLiveDataซึ่งหมายความว่าตัวแปรnightsมีLiveDataที่Roomคอยอัปเดตอยู่ และคุณสามารถสังเกตnightsเพื่อดูว่ามีการเปลี่ยนแปลงเมื่อใด - เปิด
SleepTrackerFragment - ใน
onCreateView()ให้สร้าง Observer ในตัวแปรnightsใต้การสร้างadapter
การระบุviewLifecycleOwnerของ Fragment เป็นเจ้าของวงจรจะช่วยให้มั่นใจได้ว่า Observer นี้จะทำงานเฉพาะเมื่อRecyclerViewอยู่บนหน้าจอเท่านั้น
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
})- ภายใน Observer ทุกครั้งที่คุณได้รับค่าที่ไม่ใช่ Null (สำหรับ
nights) ให้กำหนดค่าให้กับdataของอแดปเตอร์ นี่คือโค้ดที่เสร็จสมบูรณ์สำหรับ Observer และการตั้งค่าข้อมูล
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.data = it
}
})- สร้างและเรียกใช้โค้ด
คุณจะเห็นตัวเลขคุณภาพการนอนหลับเป็นรายการ หากอะแดปเตอร์ทำงาน ภาพหน้าจอด้านซ้ายแสดง -1 หลังจากที่คุณแตะเริ่ม ภาพหน้าจอด้านขวาแสดงหมายเลขคุณภาพการนอนหลับที่อัปเดตแล้วหลังจากที่คุณแตะหยุดและเลือกคะแนนคุณภาพ

ขั้นตอนที่ 6: ดูวิธีรีไซเคิลที่ใส่ภาพ
RecyclerView รีไซเคิลตัวยึดมุมมอง ซึ่งหมายความว่าตัวยึดมุมมองจะนำกลับมาใช้ซ้ำ เมื่อมุมมองเลื่อนออกจากหน้าจอ RecyclerView จะนำมุมมองนั้นกลับมาใช้ใหม่สำหรับมุมมองที่กำลังจะเลื่อนเข้ามาในหน้าจอ
เนื่องจากมีการนำตัวยึดมุมมองเหล่านี้กลับมาใช้ใหม่ โปรดตรวจสอบว่า onBindViewHolder() ตั้งค่าหรือรีเซ็ตการปรับแต่งใดๆ ที่รายการก่อนหน้าอาจตั้งค่าไว้ในตัวยึดมุมมอง
เช่น คุณอาจตั้งค่าสีข้อความเป็นสีแดงในตัวยึดมุมมองที่เก็บคะแนนคุณภาพซึ่งน้อยกว่าหรือเท่ากับ 1 และแสดงถึงการนอนหลับที่ไม่ดี
- ใน
SleepNightAdapterclass ให้เพิ่มโค้ดต่อไปนี้ที่ส่วนท้ายของonBindViewHolder()
if (item.sleepQuality <= 1) {
holder.textView.setTextColor(Color.RED) // red
}- เรียกใช้แอป
- เพิ่มข้อมูลคุณภาพการนอนหลับต่ำ แล้วตัวเลขจะเป็นสีแดง
- ให้คะแนนคุณภาพการนอนหลับสูงจนกว่าคุณจะเห็นตัวเลขสีแดงสูงบนหน้าจอ
เนื่องจากRecyclerViewใช้ตัวยึดมุมมองซ้ำ ในที่สุดก็จะใช้ตัวยึดมุมมองสีแดงตัวใดตัวหนึ่งซ้ำสำหรับการให้คะแนนคุณภาพสูง ระบบแสดงการจัดประเภทสูงเป็นสีแดงอย่างไม่ถูกต้อง

- หากต้องการแก้ไขปัญหานี้ ให้เพิ่มคำสั่ง
elseเพื่อตั้งค่าสีเป็นดำหากคุณภาพไม่น้อยกว่าหรือเท่ากับ 1
เมื่อระบุเงื่อนไขทั้ง 2 อย่างชัดเจน ตัวยึดมุมมองจะใช้สีข้อความที่ถูกต้องสำหรับแต่ละรายการ
if (item.sleepQuality <= 1) {
holder.textView.setTextColor(Color.RED) // red
} else {
// reset
holder.textView.setTextColor(Color.BLACK) // black
}- เรียกใช้แอป แล้วตัวเลขควรมีสีที่ถูกต้องเสมอ
ยินดีด้วย ตอนนี้คุณมี RecyclerView พื้นฐานที่ทำงานได้อย่างเต็มรูปแบบแล้ว
ในงานนี้ คุณจะแทนที่ตัวยึดมุมมองแบบง่ายด้วยตัวยึดที่แสดงข้อมูลเพิ่มเติมสำหรับการนอนหลับในคืนหนึ่งได้
ViewHolder ง่ายๆ ที่คุณเพิ่มลงใน Util.kt จะครอบ TextView ใน TextItemViewHolder
class TextItemViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView)แล้วทำไม RecyclerView ไม่ใช้ TextView โดยตรง โค้ดบรรทัดเดียวนี้มีฟังก์ชันการทำงานมากมาย ViewHolder อธิบายมุมมองไอเทมและข้อมูลเมตาเกี่ยวกับตำแหน่งของไอเทมภายใน RecyclerView RecyclerView อาศัยฟังก์ชันนี้เพื่อจัดตำแหน่งมุมมองอย่างถูกต้องขณะที่รายการเลื่อน และเพื่อทำสิ่งต่างๆ ที่น่าสนใจ เช่น ทำให้มุมมองเคลื่อนไหวเมื่อมีการเพิ่มหรือนำรายการออกใน Adapter
หาก RecyclerView จำเป็นต้องเข้าถึงมุมมองที่จัดเก็บไว้ใน ViewHolder ก็สามารถทำได้โดยใช้พร็อพเพอร์ตี้ itemView ของผู้ถือมุมมอง RecyclerView ใช้ itemView เมื่อเชื่อมโยงรายการเพื่อแสดงบนหน้าจอ เมื่อวาดการตกแต่งรอบๆ มุมมอง เช่น เส้นขอบ และเมื่อใช้การช่วยเหลือพิเศษ
ขั้นตอนที่ 1: สร้างเลย์เอาต์ของรายการ
ในขั้นตอนนี้ คุณจะได้สร้างไฟล์เลย์เอาต์สำหรับ 1 รายการ เลย์เอาต์ประกอบด้วย ConstraintLayout ที่มี ImageView สำหรับคุณภาพการนอนหลับ TextView สำหรับระยะเวลาการนอนหลับ และ TextView สำหรับคุณภาพเป็นข้อความ เนื่องจากคุณเคยทำเลย์เอาต์มาก่อน ให้คัดลอกและวางโค้ด XML ที่ให้ไว้
- สร้างไฟล์ทรัพยากรเลย์เอาต์ใหม่และตั้งชื่อเป็น
list_item_sleep_night - แทนที่โค้ดทั้งหมดในไฟล์ด้วยโค้ดด้านล่าง จากนั้นทำความคุ้นเคยกับเลย์เอาต์ที่คุณเพิ่งสร้าง
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/quality_image"
android:layout_width="@dimen/icon_size"
android:layout_height="60dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@drawable/ic_sleep_5" />
<TextView
android:id="@+id/sleep_length"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/quality_image"
app:layout_constraintTop_toTopOf="@+id/quality_image"
tools:text="Wednesday" />
<TextView
android:id="@+id/quality_string"
android:layout_width="0dp"
android:layout_height="20dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="@+id/sleep_length"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/sleep_length"
app:layout_constraintTop_toBottomOf="@+id/sleep_length"
tools:text="Excellent!!!" />
</androidx.constraintlayout.widget.ConstraintLayout>- เปลี่ยนไปที่แท็บออกแบบใน Android Studio ในมุมมองการออกแบบ เลย์เอาต์จะมีลักษณะคล้ายกับภาพหน้าจอด้านซ้ายด้านล่าง ในมุมมองพิมพ์เขียว จะมีลักษณะเหมือนภาพหน้าจอด้านขวา

ขั้นตอนที่ 2: สร้าง ViewHolder
- เปิด
SleepNightAdapter.kt - สร้างคลาสภายใน
SleepNightAdapterชื่อViewHolderและทำให้คลาสขยายRecyclerView.ViewHolder
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){}- ดูข้อมูลอ้างอิงถึงมุมมองต่างๆ ได้ใน
ViewHolderคุณต้องมีข้อมูลอ้างอิงถึงมุมมองที่ViewHolderนี้จะอัปเดต ทุกครั้งที่คุณผูกViewHolderนี้ คุณจะต้องเข้าถึงรูปภาพและทั้งมุมมองข้อความ (คุณจะแปลงโค้ดนี้เพื่อใช้การเชื่อมโยงข้อมูลในภายหลัง)
val sleepLength: TextView = itemView.findViewById(R.id.sleep_length)
val quality: TextView = itemView.findViewById(R.id.quality_string)
val qualityImage: ImageView = itemView.findViewById(R.id.quality_image)ขั้นตอนที่ 3: ใช้ ViewHolder ใน SleepNightAdapter
- ในคำจำกัดความของ
SleepNightAdapterให้ใช้SleepNightAdapter.ViewHolderที่คุณเพิ่งสร้างแทนTextItemViewHolder
class SleepNightAdapter: RecyclerView.Adapter<SleepNightAdapter.ViewHolder>() {อัปเดต onCreateViewHolder():
- เปลี่ยนลายเซ็นของ
onCreateViewHolder()เพื่อส่งคืนViewHolder - เปลี่ยน LayoutInflator เพื่อใช้ทรัพยากรเลย์เอาต์ที่ถูกต้อง
list_item_sleep_night - นำการแคสต์ไปยัง
TextViewออก - ให้แสดงผล
ViewHolderแทนที่จะแสดงผลTextItemViewHolder
นี่คือฟังก์ชันonCreateViewHolder()ที่อัปเดตแล้ว
override fun onCreateViewHolder(
parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater =
LayoutInflater.from(parent.context)
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night,
parent, false)
return ViewHolder(view)
}อัปเดต onBindViewHolder():
- เปลี่ยนลายเซ็นของ
onBindViewHolder()เพื่อให้พารามิเตอร์holderเป็นViewHolderแทนที่จะเป็นTextItemViewHolder - ใน
onBindViewHolder()ให้ลบโค้ดทั้งหมด ยกเว้นคำจำกัดความของitem - กำหนด
valresที่มีข้อมูลอ้างอิงถึงresourcesสำหรับมุมมองนี้
val res = holder.itemView.context.resources- ตั้งค่าข้อความของมุมมองข้อความ
sleepLengthเป็นระยะเวลา คัดลอกโค้ดด้านล่าง ซึ่งเรียกใช้ฟังก์ชันการจัดรูปแบบที่มาพร้อมกับโค้ดเริ่มต้น
holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)- ซึ่งจะทำให้เกิดข้อผิดพลาด เนื่องจากต้องกำหนด
convertDurationToFormatted()เปิดUtil.ktและยกเลิกการแสดงความคิดเห็นของโค้ดและการนำเข้าที่เกี่ยวข้อง (เลือกโค้ด > แสดงความคิดเห็นด้วยความคิดเห็นระดับบรรทัด) - กลับไปที่
onBindViewHolder()แล้วใช้convertNumericQualityToString()เพื่อตั้งค่าคุณภาพ
holder.quality.text= convertNumericQualityToString(item.sleepQuality, res)- คุณอาจต้องนำเข้าฟังก์ชันเหล่านี้ด้วยตนเอง
import com.example.android.trackmysleepquality.convertDurationToFormatted
import com.example.android.trackmysleepquality.convertNumericQualityToString- ตั้งค่าไอคอนที่ถูกต้องสำหรับคุณภาพ เราได้จัดเตรียมไอคอน
ic_sleep_activeใหม่ไว้ให้คุณในโค้ดเริ่มต้น
holder.qualityImage.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
})- นี่คือฟังก์ชัน
onBindViewHolder()ที่อัปเดตเสร็จแล้ว ซึ่งตั้งค่าข้อมูลทั้งหมดสำหรับViewHolder
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = data[position]
val res = holder.itemView.context.resources
holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
holder.quality.text= convertNumericQualityToString(item.sleepQuality, res)
holder.qualityImage.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
})
}- เรียกใช้แอป จอแสดงผลควรมีลักษณะเหมือนภาพหน้าจอด้านล่าง ซึ่งแสดงไอคอนคุณภาพการนอนหลับ พร้อมข้อความสำหรับระยะเวลาการนอนหลับและคุณภาพการนอนหลับ

RecyclerView เสร็จสมบูรณ์แล้ว คุณได้เรียนรู้วิธีใช้ Adapter และ ViewHolder รวมถึงนำทั้ง 2 อย่างมารวมกันเพื่อแสดงรายการที่มี RecyclerView Adapter
โค้ดของคุณจนถึงตอนนี้แสดงกระบวนการสร้างอะแดปเตอร์และตัวยึดมุมมอง แต่คุณสามารถปรับปรุงโค้ดนี้ได้ โค้ดที่ใช้แสดงและโค้ดที่ใช้จัดการตัวยึดมุมมองจะปะปนกัน และ onBindViewHolder() ทราบรายละเอียดเกี่ยวกับวิธีอัปเดต ViewHolder
ในแอปเวอร์ชันที่ใช้งานจริง คุณอาจมีตัวยึดมุมมองหลายรายการ อะแดปเตอร์ที่ซับซ้อนมากขึ้น และนักพัฒนาแอปหลายคนที่ทำการเปลี่ยนแปลง คุณควรจัดโครงสร้างโค้ดเพื่อให้ทุกอย่างที่เกี่ยวข้องกับตัวยึดมุมมองอยู่ในตัวยึดมุมมองเท่านั้น
ขั้นตอนที่ 1: ปรับโครงสร้าง onBindViewHolder()
ในขั้นตอนนี้ คุณจะปรับโครงสร้างโค้ดและย้ายฟังก์ชันทั้งหมดของตัวยึดมุมมองไปยัง ViewHolder การปรับโครงสร้างโค้ดนี้ไม่ได้มีวัตถุประสงค์เพื่อเปลี่ยนลักษณะที่แอปปรากฏต่อผู้ใช้ แต่เพื่อให้การทำงานกับโค้ดง่ายและปลอดภัยยิ่งขึ้นสำหรับนักพัฒนาแอป โชคดีที่ Android Studio มีเครื่องมือที่จะช่วยคุณได้
- ใน
SleepNightAdapterในonBindViewHolder()ให้เลือกทุกอย่างยกเว้นคำสั่งเพื่อประกาศตัวแปรitem - คลิกขวา แล้วเลือกจัดระเบียบใหม่ > แยก > ฟังก์ชัน
- ตั้งชื่อฟังก์ชัน
bindและยอมรับพารามิเตอร์ที่แนะนำ คลิกตกลง
ฟังก์ชันbind()จะอยู่ใต้onBindViewHolder()
private fun bind(holder: ViewHolder, item: SleepNight) {
val res = holder.itemView.context.resources
holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
holder.quality.text = convertNumericQualityToString(item.sleepQuality, res)
holder.qualityImage.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
})
}- วางเคอร์เซอร์บนคำว่า
holderของพารามิเตอร์holderของbind()กดAlt+Enter(Option+Enterใน Mac) เพื่อเปิดเมนูความตั้งใจ เลือกแปลงพารามิเตอร์เป็นตัวรับเพื่อแปลงเป็นฟังก์ชันส่วนขยายที่มีลายเซ็นต่อไปนี้
private fun ViewHolder.bind(item: SleepNight) {...}- ตัดและวางฟังก์ชัน
bind()ลงในViewHolder - ตั้งค่า
bind()เป็นสาธารณะ - นำเข้า
bind()ลงในอะแดปเตอร์ หากจำเป็น - เนื่องจากตอนนี้อยู่ใน
ViewHolderแล้ว คุณจึงนำส่วนViewHolderของลายเซ็นออกได้ นี่คือโค้ดสุดท้ายสำหรับฟังก์ชันbind()ในคลาสViewHolder
fun bind(item: SleepNight) {
val res = itemView.context.resources
sleepLength.text = convertDurationToFormatted(
item.startTimeMilli, item.endTimeMilli, res)
quality.text = convertNumericQualityToString(
item.sleepQuality, res)
qualityImage.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: ปรับโครงสร้าง onCreateViewHolder
ขณะนี้ onCreateViewHolder() ในอแดปเตอร์จะขยายมุมมองจากแหล่งข้อมูลเลย์เอาต์สำหรับ ViewHolder อย่างไรก็ตาม เงินเฟ้อไม่เกี่ยวข้องกับอะแดปเตอร์ แต่เกี่ยวข้องกับViewHolder ภาวะเงินเฟ้อควรเกิดขึ้นใน ViewHolder
- ใน
onCreateViewHolder()ให้เลือกโค้ดทั้งหมดในส่วนเนื้อหาของฟังก์ชัน - คลิกขวา แล้วเลือกจัดระเบียบใหม่ > แยก > ฟังก์ชัน
- ตั้งชื่อฟังก์ชัน
fromและยอมรับพารามิเตอร์ที่แนะนำ คลิกตกลง - วางเคอร์เซอร์บนชื่อฟังก์ชัน
fromกดAlt+Enter(Option+Enterใน Mac) เพื่อเปิดเมนูความตั้งใจ - เลือกย้ายไปยังออบเจ็กต์เสริม ฟังก์ชัน
from()ต้องอยู่ในออบเจ็กต์คู่เพื่อให้เรียกใช้ในคลาสViewHolderได้ ไม่ใช่เรียกใช้ในอินสแตนซ์ViewHolder - ย้ายออบเจ็กต์
companionไปยังคลาสViewHolder - ตั้งค่า
from()เป็นสาธารณะ - ใน
onCreateViewHolder()ให้เปลี่ยนคำสั่งreturnเพื่อแสดงผลลัพธ์ของการเรียกfrom()ในคลาสViewHolder
เมธอดonCreateViewHolder()และfrom()ที่เสร็จสมบูรณ์แล้วควรมีลักษณะเหมือนโค้ดด้านล่าง และโค้ดควรสร้างและเรียกใช้ได้โดยไม่มีข้อผิดพลาด
override fun onCreateViewHolder(parent: ViewGroup, viewType:
Int): ViewHolder {
return ViewHolder.from(parent)
}companion object {
fun from(parent: ViewGroup): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
return ViewHolder(view)
}
}- เปลี่ยนลายเซ็นของคลาส
ViewHolderเพื่อให้ตัวสร้างเป็นแบบส่วนตัว เนื่องจากตอนนี้from()เป็นเมธอดที่แสดงผลอินสแตนซ์ViewHolderใหม่ จึงไม่มีเหตุผลที่ใครจะเรียกใช้ตัวสร้างของViewHolderอีกต่อไป
class ViewHolder private constructor(itemView: View) : RecyclerView.ViewHolder(itemView){- เรียกใช้แอป แอปควรสร้างและเรียกใช้ได้เหมือนเดิม ซึ่งเป็นผลลัพธ์ที่ต้องการหลังจากการปรับโครงสร้าง
โปรเจ็กต์ Android Studio: RecyclerViewFundamentals
- การแสดงรายการหรือตารางกริดของข้อมูลเป็นหนึ่งในงาน UI ที่พบบ่อยที่สุดใน Android
RecyclerViewได้รับการออกแบบมาให้มีประสิทธิภาพแม้จะแสดงรายการขนาดใหญ่มากก็ตาม RecyclerViewจะทำงานเฉพาะที่จำเป็นต่อการประมวลผลหรือวาดรายการที่มองเห็นได้บนหน้าจอในขณะนั้นเท่านั้น- เมื่อรายการเลื่อนออกจากหน้าจอ ระบบจะนำมุมมองของรายการนั้นกลับมาใช้ใหม่ ซึ่งหมายความว่ารายการนั้นจะเต็มไปด้วยเนื้อหาใหม่ที่เลื่อนเข้ามาในหน้าจอ
- รูปแบบอะแดปเตอร์ในวิศวกรรมซอฟต์แวร์ช่วยให้ออบเจ็กต์ทำงานร่วมกับ API อื่นได้
RecyclerViewใช้อะแดปเตอร์เพื่อแปลงข้อมูลแอปเป็นสิ่งที่แสดงได้โดยไม่ต้องเปลี่ยนวิธีที่แอปจัดเก็บและประมวลผลข้อมูล
หากต้องการแสดงข้อมูลใน RecyclerView คุณต้องมีส่วนต่อไปนี้
- RecyclerView
หากต้องการสร้างอินสแตนซ์ของRecyclerViewให้กำหนดองค์ประกอบ<RecyclerView>ในไฟล์เลย์เอาต์ - LayoutManager
RecyclerViewใช้LayoutManagerเพื่อจัดระเบียบเลย์เอาต์ของรายการในRecyclerViewเช่น การจัดวางในตารางกริดหรือในรายการเชิงเส้น
ใน<RecyclerView>ในไฟล์เลย์เอาต์ ให้ตั้งค่าแอตทริบิวต์app:layoutManagerเป็น LayoutManager (เช่นLinearLayoutManagerหรือGridLayoutManager)
คุณยังตั้งค่าLayoutManagerสำหรับRecyclerViewโดยใช้โปรแกรมได้ด้วย (เราจะอธิบายเทคนิคนี้ใน Codelab ในภายหลัง) - เลย์เอาต์สำหรับแต่ละรายการ
สร้างเลย์เอาต์สำหรับข้อมูล 1 รายการในไฟล์เลย์เอาต์ XML - Adapter
สร้าง Adapter ที่เตรียมข้อมูลและวิธีแสดงข้อมูลในViewHolderเชื่อมโยงอะแดปเตอร์กับRecyclerView
เมื่อRecyclerViewทำงาน ระบบจะใช้อะแดปเตอร์เพื่อดูวิธีแสดงข้อมูลบนหน้าจอ
อะแดปเตอร์กำหนดให้คุณใช้เมธอดต่อไปนี้
–getItemCount()เพื่อแสดงจำนวนรายการ
–onCreateViewHolder()เพื่อแสดงViewHolderสำหรับรายการในลิสต์
–onBindViewHolder()เพื่อปรับข้อมูลให้เข้ากับมุมมองสำหรับรายการในลิสต์ - ViewHolder
ViewHolderมีข้อมูลมุมมองสำหรับการแสดงสินค้า 1 รายการจากเลย์เอาต์ของสินค้า onBindViewHolder()วิธีการในอแดปเตอร์จะปรับข้อมูลให้เข้ากับมุมมอง คุณจะลบล้างวิธีการนี้ได้เสมอ โดยปกติแล้วonBindViewHolder()จะขยายเลย์เอาต์สำหรับรายการ และวางข้อมูลในมุมมองในเลย์เอาต์- เนื่องจาก
RecyclerViewไม่ทราบข้อมูลใดๆAdapterจึงต้องแจ้งให้RecyclerViewทราบเมื่อข้อมูลมีการเปลี่ยนแปลง ใช้notifyDataSetChanged()เพื่อแจ้งให้Adapterทราบว่าข้อมูลมีการเปลี่ยนแปลง
หลักสูตร Udacity:
เอกสารประกอบสำหรับนักพัฒนาแอป Android
ส่วนนี้แสดงรายการการบ้านที่เป็นไปได้สำหรับนักเรียน/นักศึกษาที่กำลังทำ Codelab นี้เป็นส่วนหนึ่งของหลักสูตรที่สอนโดยผู้สอน ผู้สอนมีหน้าที่ดำเนินการต่อไปนี้
- มอบหมายการบ้านหากจำเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานที่ได้รับมอบหมาย
- ให้คะแนนงานการบ้าน
ผู้สอนสามารถใช้คำแนะนำเหล่านี้ได้มากน้อยตามที่ต้องการ และควรมีอิสระในการมอบหมายการบ้านอื่นๆ ที่เห็นว่าเหมาะสม
หากคุณกำลังทำ Codelab นี้ด้วยตนเอง โปรดใช้แบบฝึกหัดเหล่านี้เพื่อทดสอบความรู้ของคุณ
ตอบคำถามต่อไปนี้
คำถามที่ 1
RecyclerView แสดงรายการอย่างไร เลือกได้มากกว่า 1 ข้อ
▢ แสดงรายการในรูปแบบรายการหรือตารางกริด
▢ เลื่อนในแนวตั้งหรือแนวนอน
▢ เลื่อนในแนวทแยงบนอุปกรณ์ขนาดใหญ่ เช่น แท็บเล็ต
▢ อนุญาตเลย์เอาต์ที่กำหนดเองเมื่อรายการหรือตารางไม่เพียงพอสำหรับกรณีการใช้งาน
คำถามที่ 2
การใช้ RecyclerView มีประโยชน์อย่างไร เลือกได้มากกว่า 1 ข้อ
▢ แสดงรายการขนาดใหญ่อย่างมีประสิทธิภาพ
▢ อัปเดตข้อมูลโดยอัตโนมัติ
▢ ลดความจำเป็นในการรีเฟรชเมื่อมีการอัปเดต ลบ หรือเพิ่มรายการลงในลิสต์
▢ ใช้ซ้ำมุมมองที่เลื่อนออกนอกหน้าจอเพื่อแสดงรายการถัดไปที่เลื่อนบนหน้าจอ
คำถามที่ 3
เหตุผลบางประการในการใช้อะแดปเตอร์มีอะไรบ้าง เลือกได้มากกว่า 1 ข้อ
▢ การแยกความกังวลทำให้การเปลี่ยนแปลงและทดสอบโค้ดง่ายขึ้น
▢ RecyclerView ไม่ขึ้นอยู่กับข้อมูลที่แสดง
▢ เลเยอร์การประมวลผลข้อมูลไม่จำเป็นต้องกังวลเกี่ยวกับวิธีแสดงข้อมูล
▢ แอปจะทำงานเร็วขึ้น
คำถามที่ 4
ข้อใดต่อไปนี้เป็นจริงเกี่ยวกับ ViewHolder เลือกได้มากกว่า 1 ข้อ
▢ ViewHolderเลย์เอาต์กำหนดไว้ในไฟล์เลย์เอาต์ XML
▢ มี ViewHolder 1 รายการสําหรับข้อมูลแต่ละหน่วยในชุดข้อมูล
▢ คุณมี ViewHolder ได้มากกว่า 1 รายการใน RecyclerView
▢ Adapter จะเชื่อมโยงข้อมูลกับ ViewHolder
เริ่มบทเรียนถัดไป: