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" />
- ให้
RecyclerView
id
จาก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 ลงใน
RecyclerView
XML ทุก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
ให้สร้างตัวแปรlistOf
SleepNight
เพื่อเก็บข้อมูล
var data = listOf<SleepNight>()
- ใน
SleepNightAdapter
ให้ลบล้างgetItemCount()
เพื่อแสดงขนาดของรายการคืนที่นอนหลับในdata
RecyclerView
ต้องทราบจำนวนรายการที่อะแดปเตอร์มีเพื่อแสดง และจะทำได้โดยการเรียกใช้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 คุณจะส่งบริบทของparent
ViewGroup เสมอ ซึ่งก็คือ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 และแสดงถึงการนอนหลับที่ไม่ดี
- ใน
SleepNightAdapter
class ให้เพิ่มโค้ดต่อไปนี้ที่ส่วนท้ายของ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
- กำหนด
val
res
ที่มีข้อมูลอ้างอิงถึง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
เริ่มบทเรียนถัดไป: