RecyclerView คืออะไร

และปัญหาที่พบบ่อย

Travis P
Black Lens
2 min readJan 13, 2017

--

หลักการทำงานของ RecyclerView

เจ้า RecyclerView เนี่ย เกิดมาเพื่อจัดการกับกรณีที่เรามีข้อมูลต้องแสดงเยอะๆ เช่นแสดงรายชื่อเพื่อนในเฟสบุคทั้งหมด อาจจะมี 1000 คน ถ้าไม่มี RecyclerView เราก็ต้องใส่ทั้ง 1000 คนใน ScrollView แทน ก็จะมี 1000 TextView ใน ScrollView เป็นการสิ้นเปลือง memory มากๆ ทั้งๆที่หน้าจอมือถือเราอาจจะเห็นแค่ทีละ 10 คน สิ่งที่ RecyclerView ทำให้เราคือ สร้าง TextView แค่ 10 อันเพื่อแสดงผลแค่ทีละ 10 ชื่อ พอเรา scroll ลงมา มันก็จะเอา TextView อันที่ไหลออกนอกจอเราไปนั้นแหละมาใส่ชื่อเพื่อนคนใหม่ให้ โดยที่ไม่ต้องสร้าง View ใหม่ให้สิ้นเปลือง

การใช้งาน RecyclerView เราต้องสร้าง RecyclerView.ViewHolder ก่อน ผมขอย้อนประวัติศาสตร์นิดนึง สมัยที่ยังใช้ ListView อยู่เรามักจะ inflate layout และ findViewById() ใหม่ทุกครั้งที่ไอเทมใหม่ scroll เข้าจอมา ซึ่งเป็นการทำงานหนักเพิ่มโดยไม่จำเป็น จึงเกิด pattern ViewHolder ขึ้นมา และพัฒนามาเป็น RecyclerView จนถึงทุกวันนี้ สังเกตว่าเราจะ findViewById() เพียงครั้งเดียวใน constructor หลังจากนั้นเราก็สามารถเรียกใช้ view ต่างๆได้จากตัวแปรเลย

จากนั้นต้องสร้าง RecyclerView.Adapter ด้วยการ override 3 methods คือ

  1. onCreateViewHolder() อันนี้จะถูกเรียกเพื่อให้เราสร้าง view แล้วเก็บไว้ใน ViewHolder ซึ่งจะสร้างตามจำนวน view ที่มองเห็นบนหน้าจอ
  2. onBindViewHolder() เอาไว้บอกว่าแสดงข้อมูลยังไง อันนี้จะถูกเรียกทุกครั้งที่ข้อมูลใหม่ scroll เข้าในจอ โดยให้เราเอาข้อมูลของเราไปแสดงบน view ผ่าน ViewHolder โดยไม่สนใจว่าเป็น ViewHolder ใหม่ หรืออันที่เพิ่งถูก scroll ออกไป
  3. getItemCount() เพื่อบอกว่ามีข้อมูลกี่อัน

ปัญหาที่พบบ่อย

ผมจำได้แม่นยำเมื่อประมาณ 3 ปีก่อน ตอนที่ผมเริ่มเขียนแอนดรอยใหม่ๆ ผมมีปัญหาไอเทมงงๆใน ListView หงุดหงิดมาก แล้วก็ต้องนั่ง debug อยู่สักพักกว่าจะหาเจอ ส่วนหนึ่งเป็นเพราะผมไม่เข้าใจการทำงานจริงๆของ ListView+ViewHolder ในสมัยนั้นด้วย (หลักการทำงานเดียวกับ RecyclerView สมัยนี้)

เวลา scroll item ไป-กลับใน RecyclerView หรือ ListView+ViewHolder แล้ว item แสดงผลแปลกๆ เปลี่ยนสีมั่วบ้าง checkbox มั่วบ้าง เอาสีไอเทมนู้นไปใส่ไอเทมนี้ แก้ข้อมูลแล้ว scroll กลับมาแล้วมันเหมือนเดิม

ตัวอย่างทำการแสดงรายชื่อคนพร้อมอายุในวงวงเล็บ มี checkbox โดยจะย้อมชื่อสีแดงสำหรับคนที่อายุตั้งแต่ 30 ขึ้นไป (ดู PersonAdapter.java บรรทัดที่ 19)

วิธีแก้ปัญหา

  1. ย้อมสีมั่ว ให้ดูบรรทัดที่ 19 ครับ ถ้าอายุเกิน 30 ให้ย้อมสีแดง อันนี้ถูก แต่ถ้าเรา scroll กลับไปข้อมูลข้างบนที่อายุน้อยกว่า 30 เจ้า RecyclerView ก็จะส่ง ViewHolder อันที่ย้อมสีแดงซึ่งหลุดขอบจอไปแล้วมาให้เราใส่ข้อมูลใหม่ เราก็ใส่ข้อมูลใหม่ แต่ยังไม่ได้ย้อมสีกลับนั่นเอง วิธีแก้ก็แค่ย้อมสีกลับ อันนี้รวมไปถึงข้อมูลอื่นๆด้วย เวลามี if ให้มี else สำหรับข้อมูลปกติด้วยเสมอ
  2. checkbox มั่ว รวมถึงเวลาเปลี่ยนข้อมูลใน view แล้ว scroll กลับมากลายเป็นข้อมูลเก่าด้วย อันนี้ให้ดูบรรทัดที่ 17,18 ทุกครั้งที่เราแสดงข้อมูลเราจะหยิบ Person จาก list เรามาแล้วแสดงข้อมูลจากอันนั้นเสมอ ไม่ได้มีการบันทึกอะไรเกี่ยวกับ checkbox เลย สิ่งที่เราต้องทำก็คือหากมีการแก้ข้อมูล หรือ checkbox เราต้องบันทึกไว้กับ person นั้นไว้ด้วย เวลาเอามา bind ใหม่จะได้มีข้อมูลที่อัพเดตเสมอ (หรือจะใช้ SparseBooleanArray ก็ได้นะครับ เอาไว้เดี๋ยวเขียนวันหลัง ขอบคุณ Verachad Wongsawangtham ที่เตือนความจำ)

โปรเจคตัวอย่างสามารถดูได้ใน github

ขอขอบคุณ Johnny Dew ที่ช่วยตรวจทานมา ณ ที่นี้ด้วย

หวังว่าจะหายข้องใจกันนะครับ ช่วยกันเผยแพร่ด้วยการกด 💚 recommend หรือจะแชร์ หรือจะ follow ก็แล้วแต่สะดวกครับ แล้วพบกันใหม่บทความหน้า

--

--

Travis P
Black Lens

Android Developer, Kotlin & Flutter Enthusiast and Gamer