Codelab นี้เป็นส่วนหนึ่งของหลักสูตรพื้นฐานเกี่ยวกับ Kotlin ใน Android คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้ หากทํางานผ่าน Codelab ตามลําดับ Codelab ของหลักสูตรทั้งหมดจะแสดงอยู่ในหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals
ข้อมูลเบื้องต้น
Codelab นี้จะสอนวิธีใช้ RecyclerView
เพื่อแสดงรายการ การสร้างแอปที่ใช้ตัวติดตามการนอนหลับจากชุด Codelab ก่อนหน้านี้ คุณจะได้เรียนรู้วิธีการที่ดีและคล่องตัวมากขึ้นในการแสดงข้อมูลโดยใช้ RecyclerView
ที่มีสถาปัตยกรรมที่แนะนํา
สิ่งที่ควรทราบอยู่แล้ว
คุณควรทําความคุ้นเคยกับสิ่งต่อไปนี้
- การสร้างอินเทอร์เฟซผู้ใช้ (UI) พื้นฐานโดยใช้กิจกรรม ส่วนย่อย และข้อมูลพร็อพเพอร์ตี้
- ไปยังส่วนต่างๆ ระหว่างส่วนย่อยและใช้
safeArgs
เพื่อส่งข้อมูลระหว่างส่วนย่อย - การใช้โมเดลมุมมอง ดูโรงงานของโมเดล การเปลี่ยนรูปแบบ และ
LiveData
และการสังเกตการณ์ - การสร้างฐานข้อมูล
Room
การสร้าง DAO และการกําหนดเอนทิตี - การใช้ Coroutine สําหรับงานฐานข้อมูลและงานอื่นๆ ที่ใช้เวลานาน
สิ่งที่คุณจะได้เรียนรู้
- วิธีใช้
RecyclerView
ที่มีAdapter
และViewHolder
เพื่อแสดงรายการ
สิ่งที่คุณจะทํา
- เปลี่ยนแอป TrackMySleep Quality จากบทเรียนก่อนหน้าเพื่อใช้
RecyclerView
เพื่อแสดงข้อมูลคุณภาพการนอนหลับ
ใน Codelab นี้ คุณสร้างส่วน RecyclerView
ของแอปที่ติดตามคุณภาพการนอนหลับ แอปใช้ฐานข้อมูล Room
เพื่อจัดเก็บข้อมูลการนอนหลับเมื่อเวลาผ่านไป
แอปติดตามการนอนหลับเริ่มต้นมีหน้าจอ 2 หน้าจอซึ่งแสดงด้วยส่วนย่อยดังที่แสดงในภาพด้านล่าง
หน้าจอแรกที่แสดงทางด้านซ้ายมีปุ่มให้เริ่มและหยุดการติดตาม หน้าจอนี้ยังแสดงข้อมูลการนอนหลับของผู้ใช้ทั้งหมดด้วย ปุ่มล้างจะลบข้อมูลทั้งหมดที่แอปรวบรวมให้กับผู้ใช้อย่างถาวร หน้าจอที่ 2 ที่แสดงทางด้านขวาคือการเลือกคะแนนคุณภาพการนอนหลับ
แอปนี้ใช้สถาปัตยกรรมที่เรียบง่ายด้วยตัวควบคุม UI, ViewModel
และ LiveData
แอปยังใช้ฐานข้อมูล Room
เพื่อทําให้ข้อมูลการนอนหลับคงอยู่ถาวร
รายการการนอนหลับตอนกลางคืนที่แสดงในหน้าจอแรกใช้งานได้ แต่ไม่ค่อยสวย แอปใช้ตัวจัดรูปแบบที่ซับซ้อนเพื่อสร้างสตริงข้อความสําหรับมุมมองข้อความและตัวเลขเพื่อคุณภาพ นอกจากนี้ การออกแบบนี้ยังใช้ไม่ได้กับ หลังจากที่คุณแก้ไขปัญหาเหล่านี้ทั้งหมดใน Codelab แล้ว แอปสุดท้ายจะมีฟังก์ชันการทํางานเหมือนกันและหน้าจอหลักจะมีลักษณะดังนี้
การแสดงรายการหรือตารางกริดข้อมูลเป็นหนึ่งในงาน UI ที่พบบ่อยที่สุดใน Android ข้อมูลมีตั้งแต่แบบง่ายไปจนถึงซับซ้อนมาก รายการมุมมองข้อความอาจแสดงข้อมูลแบบง่าย เช่น รายการช็อปปิ้ง รายการที่ซับซ้อน เช่น รายการสถานที่พักผ่อนที่มีคําอธิบายประกอบ อาจแสดงรายละเอียดหลายอย่างแก่ผู้ใช้ภายในตารางกริดแบบเลื่อนที่มีส่วนหัว
Android มีวิดเจ็ต RecyclerView
เพื่อรองรับ Use Case เหล่านี้ทั้งหมด
ประโยชน์ที่ดีที่สุดของ RecyclerView
คือมีประสิทธิภาพมากสําหรับรายการขนาดใหญ่ ดังนี้
- โดยค่าเริ่มต้น
RecyclerView
จะทํางานหรือวาดภาพเฉพาะรายการที่ปรากฏบนหน้าจอเท่านั้น ตัวอย่างเช่น หากรายการมีองค์ประกอบ 1,000 รายการ แต่มีองค์ประกอบเพียง 10 รายการเท่านั้นRecyclerView
จะทํางานมากพอที่จะวาดได้ 10 รายการบนหน้าจอ เมื่อผู้ใช้เลื่อนหน้าจอRecyclerView
จะพิจารณาว่าสินค้าใหม่ควรอยู่ที่หน้าจอใดและทํางานได้มากพอที่จะแสดงรายการเหล่านั้น - เมื่อมีการเลื่อนรายการออกจากหน้าจอ มุมมองของรายการนั้นจะถูกรีไซเคิล ซึ่งหมายความว่ารายการจะมีเนื้อหาใหม่ที่เลื่อนเข้ามาบนหน้าจอ ลักษณะการทํางานของ
RecyclerView
นี้ช่วยประหยัดเวลาในการประมวลผลอย่างมากและช่วยให้รายการเลื่อนดูได้อย่างราบรื่น - เมื่อมีการเปลี่ยนแปลงรายการ
RecyclerView
จะอัปเดตรายการนั้นแทนที่จะแทนที่จะแสดงรายการทั้งหมดใหม่ รายการนี้มีประสิทธิภาพเพิ่มขึ้นมากเมื่อแสดงรายการที่ซับซ้อน
ในลําดับที่แสดงด้านล่าง คุณจะเห็นข้อมูลพร็อพเพอร์ตี้ 1 รายการ ABC
หลังจากที่มุมมองดังกล่าวเลื่อนหน้าจอออกแล้ว RecyclerView
จะนํามุมมองใหม่มาใช้ใหม่ในข้อมูล XYZ
รูปแบบอะแดปเตอร์
หากคุณเคยเดินทางระหว่างประเทศที่ใช้เต้ารับไฟฟ้าที่แตกต่างกัน คุณคงทราบวิธีเสียบอุปกรณ์เข้ากับเต้ารับโดยใช้อะแดปเตอร์ อะแดปเตอร์ช่วยให้คุณแปลงปลั๊กประเภทหนึ่งเป็นอีกประเภทหนึ่งได้ ซึ่งเป็นการแปลงอินเทอร์เฟซหนึ่งให้ใช้กับอีกแบบหนึ่งจริงๆ
รูปแบบอะแดปเตอร์ในวิศวกรรมซอฟต์แวร์ช่วยให้วัตถุทํางานกับ API อื่นได้ RecyclerView
ใช้อะแดปเตอร์เพื่อแปลงข้อมูลแอปเป็นสิ่งที่ RecyclerView
แสดงได้ โดยไม่ต้องเปลี่ยนแปลงวิธีที่แอปจัดเก็บและประมวลผลข้อมูล สําหรับแอปติดตามการนอนหลับ คุณจะต้องสร้างอะแดปเตอร์ที่ใช้ข้อมูลจากฐานข้อมูล Room
เพื่อทําให้ RecyclerView
รู้วิธีแสดงโดยไม่ต้องเปลี่ยน ViewModel
การใช้ RecyclerView
หากต้องการแสดงข้อมูลใน RecyclerView
คุณต้องมีส่วนต่อไปนี้
- ข้อมูลที่จะแสดง
- อินสแตนซ์
RecyclerView
ที่กําหนดไว้ในไฟล์เลย์เอาต์เพื่อทําหน้าที่เป็นคอนเทนเนอร์สําหรับมุมมอง - เลย์เอาต์ของข้อมูล 1 รายการ
หากรายการสิ่งของทั้งหมดดูเหมือนกัน คุณจะใช้เลย์เอาต์เดียวกันสําหรับแต่ละรายการได้ แต่ไม่บังคับ คุณต้องสร้างเลย์เอาต์รายการแยกจากเลย์เอาต์ส่วนย่อยเพื่อให้สร้างมุมมองรายการได้ครั้งละ 1 รายการและกรอกข้อมูล - เครื่องมือจัดการเลย์เอาต์
ตัวจัดการเลย์เอาต์จะจัดการองค์กร (เลย์เอาต์) ของคอมโพเนนต์ UI ในข้อมูลพร็อพเพอร์ตี้ - ผู้ถือครองมุมมอง
ผู้ถือมุมมองจะขยายชั้นViewHolder
โดยจะมีข้อมูลมุมมองสําหรับการแสดงสินค้า 1 รายการจากเลย์เอาต์ของสินค้า นอกจากนี้ เจ้าของข้อมูลพร็อพเพอร์ตี้ยังใส่ข้อมูลที่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 การซิงค์แอปอาจใช้เวลาสักครู่
- เปิดไฟล์โมดูล
build.gradle
เลื่อนไปที่ด้านล่าง แล้วสังเกตการขึ้นต่อกันใหม่ซึ่งดูคล้ายกับโค้ดด้านล่าง
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" />
- ให้
id
ของsleep_list
แก่RecyclerView
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"
- เพิ่มผู้จัดการเลย์เอาต์ไปยัง XML ของ
RecyclerView
ทุกRecyclerView
จําเป็นต้องมีตัวจัดการเลย์เอาต์ที่บอกวิธีวางตําแหน่งในรายการ 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()
ดังที่แสดงด้านล่าง
ฟังก์ชันonBindViewHolder()
จะเรียกใช้โดยRecyclerView
เพื่อแสดงข้อมูลของ 1 รายการในตําแหน่งที่ระบุ ดังนั้น เมธอดonBindViewHolder()
ใช้อาร์กิวเมนต์ 2 รายการ ได้แก่ ผู้ถือมุมมอง และตําแหน่งของข้อมูลเพื่อเชื่อมโยง สําหรับแอปนี้ เจ้าของคือTextItemViewHolder
และตําแหน่งจะอยู่ในรายการ
override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
}
- ภายใน
onBindViewHolder()
ให้สร้างตัวแปรสําหรับสินค้า 1 รายการที่ตําแหน่งหนึ่งๆ ในข้อมูล
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
เครื่องมือแปลนเลย์เอาต์รู้วิธีสร้างมุมมองจากเลย์เอาต์ XMLcontext
มีข้อมูลเกี่ยวกับวิธีเพิ่มมุมมองให้สูงเกินจริง ในบริบทของมุมมองนักรีไซเคิล คุณจะต้องส่งในบริบทของกลุ่มข้อมูลพร็อพเพอร์ตี้parent
ซึ่งก็คือ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
เมื่อข้อมูลที่แสดงอยู่มีการเปลี่ยนแปลง ให้เพิ่มตัวตั้งค่าที่กําหนดเองลงในตัวแปรdata
ที่อยู่ด้านบนของคลาสSleepNightAdapter
เมื่อตั้งค่าใหม่ ให้ระบุdata
ค่าใหม่ แล้วเรียกnotifyDataSetChanged()
เพื่อเรียกรายการใหม่ด้วยข้อมูลใหม่
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
}
ขั้นตอนที่ 4: บอก RecyclerView เกี่ยวกับอะแดปเตอร์
RecyclerView
จําเป็นต้องรู้เกี่ยวกับอะแดปเตอร์เพื่อใช้รับผู้ถือข้อมูลพร็อพเพอร์ตี้
- เปิด
SleepTrackerFragment.kt
- สร้างอะแดปเตอร์ใน
onCreateview()
วางโค้ดนี้หลังจากสร้างโมเดล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
เนื่องจากคุณจะสร้างการสังเกตการณ์ซึ่งจําเป็นต้องเข้าถึงตัวแปรนี้ ประกาศของคุณควรมีลักษณะเช่นนี้
val nights = database.getAllNights()
- ในแพ็กเกจ
database
ให้เปิดSleepDatabaseDao
- ค้นหาฟังก์ชัน
getAllNights()
โปรดสังเกตว่าฟังก์ชันนี้ส่งคืนรายการค่าSleepNight
เป็นLiveData
ซึ่งหมายความว่าตัวแปรnights
ประกอบด้วยLiveData
ที่Room
อัปเดตไว้ และสังเกตnights
ได้ว่ามีการเปลี่ยนแปลงเมื่อใด - เปิด
SleepTrackerFragment
- ใน
onCreateView()
ด้านล่างสร้างadapter
ให้สร้างการสังเกตการณ์ในตัวแปรnights
เมื่อระบุส่วนย่อยของviewLifecycleOwner
ในฐานะเจ้าของวงจร คุณจะมั่นใจได้ว่าผู้สังเกตการณ์นี้จะทํางานก็ต่อเมื่อRecyclerView
อยู่บนหน้าจอ
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
})
- ภายในผู้สังเกตการณ์ เมื่อได้รับค่าที่ไม่เป็นค่าว่าง (สําหรับ
nights
) ให้กําหนดค่าให้กับอะแดปเตอร์data
ของอะแดปเตอร์ นี่คือโค้ดที่สมบูรณ์สําหรับผู้สังเกตการณ์และตั้งค่าข้อมูล:
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.data = it
}
})
- สร้างและเรียกใช้โค้ด
คุณจะเห็นตัวเลขคุณภาพการนอนหลับเป็นรายการหากอะแดปเตอร์ใช้งานได้ ภาพหน้าจอทางด้านซ้ายจะแสดง -1 หลังจากแตะเริ่ม ภาพหน้าจอทางด้านขวาจะแสดงตัวเลขคุณภาพการนอนหลับที่อัปเดตหลังจากที่คุณแตะหยุด แล้วเลือกการให้คะแนนคุณภาพ
ขั้นตอนที่ 6: สํารวจว่ามีการนําผู้ถือข้อมูลพร็อพเพอร์ตี้กลับมาใช้ใหม่อย่างไร
RecyclerView
นํากลับมาใช้ใหม่โดยแสดงผู้ถือบัตร ซึ่งหมายความว่ามีการใช้ซ้ํา ขณะที่มุมมองเลื่อนหน้าจอออก RecyclerView
จะใช้มุมมองสําหรับมุมมองที่กําลังเลื่อนดูบนหน้าจออีกครั้ง
เนื่องจากเจ้าของข้อมูลพร็อพเพอร์ตี้เหล่านี้รีไซเคิลแล้ว โปรดตรวจสอบว่า onBindViewHolder()
ได้ตั้งค่าหรือรีเซ็ตการปรับแต่งที่รายการก่อนหน้าอาจมีการตั้งค่าไว้ในผู้ถือการดู
ตัวอย่างเช่น คุณสามารถตั้งค่าสีข้อความเป็นสีแดงในผู้ถือมุมมองที่แสดงคะแนนคุณภาพต่ํากว่าหรือเท่ากับ 1 และแสดงถึงการนอนหลับที่ไม่ดี
- เพิ่มรหัสต่อไปนี้ไว้ที่ท้าย
onBindViewHolder()
ในชั้นเรียนSleepNightAdapter
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
นี้ คุณต้องเข้าถึงรูปภาพและมุมมองข้อความทั้ง 2 แบบ (คุณแปลงรหัสนี้เพื่อใช้การเชื่อมโยงข้อมูลในภายหลัง)
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
- เปลี่ยนตัวแทรกเลย์เอาต์เพื่อใช้ทรัพยากรเลย์เอาต์ที่ถูกต้อง
list_item_sleep_night
- นําการแคสต์ออกจาก
TextView
- แทนที่จะส่งคืน
TextItemViewHolder
ให้แสดงผลViewHolder
นี่คือฟังก์ชัน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
และยกเลิกการแสดงความคิดเห็นเกี่ยวกับโค้ดและการนําเข้าที่เกี่ยวข้อง (เลือก Code > comment with Line comments) - กลับไปที่
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
ไปใช้แล้ว และเราได้รวบรวมไว้ด้วยกันเพื่อแสดงรายการด้วย RecyclerView
Adapter
โค้ดของคุณแสดงถึงขั้นตอนการสร้างอะแดปเตอร์และผู้ถือมุมมอง อย่างไรก็ตาม คุณสามารถปรับปรุงโค้ดนี้ได้ โค้ดที่จะแสดงและโค้ดที่ใช้จัดการผู้ถือครองข้อมูลพร็อพเพอร์ตี้จะผสมกัน และ onBindViewHolder()
จะทราบรายละเอียดเกี่ยวกับวิธีอัปเดต ViewHolder
ในแอปเวอร์ชันที่ใช้งานจริง คุณอาจมีผู้ถือข้อมูลพร็อพเพอร์ตี้หลายราย อะแดปเตอร์ที่ซับซ้อนมากขึ้น และนักพัฒนาซอฟต์แวร์หลายรายที่ทําการเปลี่ยนแปลงต่างๆ คุณควรจัดโครงสร้างโค้ดเพื่อให้ทุกสิ่งที่เกี่ยวข้องกับผู้ถือครองข้อมูลอยู่ในผู้ถือสิทธิ์เท่านั้น
ขั้นตอนที่ 1: เปลี่ยนโครงสร้าง onBindViewholder()
ในขั้นตอนนี้ คุณจะต้องเปลี่ยนโครงสร้างโค้ดและย้ายฟังก์ชันทั้งหมดของผู้ถือการดูไปยัง ViewHolder
วัตถุประสงค์ของการเปลี่ยนโครงสร้างนี้ไม่ใช่การเปลี่ยนรูปลักษณ์ของแอปต่อผู้ใช้ แต่จะช่วยให้โค้ดทํางานได้ง่ายขึ้นและปลอดภัยกว่า โชคดีที่ Android Studio มีเครื่องมือที่จะช่วยได้
- ใน
SleepNightAdapter
ในonBindViewHolder()
ให้เลือกทุกอย่างยกเว้นคําสั่งที่จะประกาศตัวแปรitem
- คลิกขวา แล้วเลือก Rector > แยก > Function
- ตั้งชื่อฟังก์ชัน
bind
และยอมรับพารามิเตอร์ที่แนะนํา คลิก OK
ฟังก์ชัน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) เพื่อเปิดเมนู Intent เลือกแปลงพารามิเตอร์เป็นผู้รับเพื่อแปลงเป็นฟังก์ชันส่วนขยายที่มีลายเซ็นต่อไปนี้
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
การเพิ่ม tCPM ควรจะเกิดขึ้นใน ViewHolder
- ใน
onCreateViewHolder()
ให้เลือกโค้ดทั้งหมดในส่วนเนื้อหาของฟังก์ชัน - คลิกขวา แล้วเลือก Rector > แยก > Function
- ตั้งชื่อฟังก์ชัน
from
และยอมรับพารามิเตอร์ที่แนะนํา คลิก OK - วางเคอร์เซอร์ไว้ที่ชื่อฟังก์ชัน
from
กดAlt+Enter
(Option+Enter
บน Mac) เพื่อเปิดเมนู Intent - เลือกย้ายไปยังออบเจ็กต์ที่แสดงร่วมกัน ฟังก์ชัน
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
เป็นตัวจัดการเลย์เอาต์ (เช่นLinearLayoutManager
หรือGridLayoutManager
)
คุณยังกําหนดLayoutManager
สําหรับRecyclerView
แบบเป็นโปรแกรมได้ (เทคนิคนี้ครอบคลุมอยู่ใน Codelab ในภายหลัง) - เลย์เอาต์ของแต่ละรายการ
สร้างเลย์เอาต์สําหรับข้อมูล 1 รายการในไฟล์เลย์เอาต์ XML - อะแดปเตอร์
สร้างอะแดปเตอร์ที่เตรียมข้อมูลและวิธีที่ข้อมูลดังกล่าวจะปรากฏใน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
เริ่มบทเรียนถัดไป: