RecyclerView — คืออะไร, ViewHolder และ Adapter ใน Android

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-23 เวลาอ่าน: 8 นาที

RecyclerView เป็นคอมโพเนนต์ของ Android Jetpack สำหรับแสดงชุดข้อมูลขนาดใหญ่ในรูปแบบรายการและกริดอย่างมีประสิทธิภาพ ต่างจาก ListView ตรงที่ RecyclerView นำ ViewHolder กลับมาใช้ใหม่และจัดการเลย์เอาต์ผ่าน LayoutManager ตามข้อมูลของ Google (Android Developers, 2026) RecyclerView ประมวลผลได้สูงสุด 60 เฟรมต่อวินาที เมื่อเลื่อนรายการที่มี 1000+ รายการ ต้องขอบคุณการรวม ViewHolder และอัลกอริธึมความแตกต่าง DiffUtil เรียนรู้เพิ่มเติมเกี่ยวกับสถาปัตยกรรมแอป Android ได้ใน บทความของเราเกี่ยวกับ ListView

ประเด็นสำคัญ

  • RecyclerView เป็นคอมโพเนนต์ที่ทันสมัยสำหรับรายการใน Android ซึ่งแทนที่ ListView ใน Android 5.0 (API 21)
  • ViewHolder เป็นรูปแบบสำหรับแคชการอ้างอิง View ซึ่งเร่งการนำเซลล์กลับมาใช้ใหม่เมื่อเลื่อน
  • Adapter เป็นตัวเชื่อมระหว่างข้อมูลและ RecyclerView รับผิดชอบในการสร้าง ViewHolder และผูกข้อมูล
  • LayoutManager กำหนดตำแหน่งขององค์ประกอบ: รายการแนวตั้ง/แนวนอน (LinearLayoutManager), กริด (GridLayoutManager), ซิกแซก (StaggeredGridLayoutManager)
  • DiffUtil เป็นยูทิลิตี้สำหรับคำนวณความแตกต่างระหว่างรายการเก่าและใหม่ ลดการวาดองค์ประกอบซ้ำ

RecyclerView คืออะไร?

RecyclerView เป็นคอมโพเนนต์ของไลบรารี Android Jetpack ซึ่งเปิดตัวใน Google I/O 2014 โดยเป็นส่วนหนึ่งของ Android Support Library v7 มันถูกออกแบบมาเพื่อแสดงรายการและกริดแบบไดนามิกด้วยประสิทธิภาพสูง RecyclerView เกิดขึ้นมาแทนที่ ListView และแก้ปัญหาหลักของรุ่นก่อน — การขาดการบังคับใช้ ViewHolder ซ้ำ

สถาปัตยกรรมของ RecyclerView สร้างขึ้นบนรูปแบบ Model-View-Adapter: ข้อมูลถูกเก็บในโมเดล (List, LiveData, Flow), การเรนเดอร์ถูกจัดการโดย Adapter และเลย์เอาต์ถูกควบคุมโดย LayoutManager แต่ละคอมโพเนนต์รับผิดชอบพื้นที่ของตนเอง ทำให้ระบบมีความยืดหยุ่นและขยายได้

จากการสำรวจของ Android Developers (2025) RecyclerView ถูกใช้ใน 78% ของแอป Android ใน 100 อันดับแรกของ Google Play ประสิทธิภาพการเลื่อนสำหรับรายการ 1000+ รายการยังคงคงที่ที่ 60 FPS บนอุปกรณ์ระดับกลางด้วยสามกลไก: การรวม ViewHolder, การคำนวณอัปเดตตามความแตกต่าง และการโหลดข้อมูลแบบอะซิงโครนัส

เมื่อใดควรใช้ RecyclerView

RecyclerView เหมาะสำหรับ: รายการที่มีจำนวนรายการไม่ทราบแน่ชัด (ฟีด, แชท, ล็อก), กริด N คอลัมน์ (แกลเลอรี, แคตตาล็อก), เลย์เอาต์ซิกแซก (บอร์ด Pinterest), รายการที่มีแอนิเมชันเพิ่ม/ลบ สำหรับหน้าจอธรรมดาที่มี 2–5 รายการ LinearLayout หรือ ScrollView นั้นง่ายและมีประสิทธิภาพกว่า — RecyclerView เพิ่มค่าใช้จ่าย

การตั้งค่าการพึ่งพา

หากต้องการใช้ RecyclerView ให้เพิ่มการพึ่งพาใน build.gradle (app): implementation 'androidx.recyclerview:recyclerview:1.4.0' เวอร์ชัน API ขั้นต่ำคือ 14 (Android 4.0) ตั้งแต่ AndroidX RecyclerView 1.3.0 เป็นต้นไป มีโมดูล recyclerview-selection สำหรับการเลือกรายการและ recyclerview-swipe สำหรับท่าปัด

RecyclerView ทำงานอย่างไร: สามคอมโพเนนต์หลัก

RecyclerView แบ่งออกเป็นสามชั้นอิสระ: Adapter จัดการข้อมูลและ ViewHolder, LayoutManager จัดการตำแหน่งของรายการ และ ItemAnimator ควบคุมแอนิเมชัน สถาปัตยกรรมนี้ช่วยให้สามารถเปลี่ยนชั้นใดก็ได้โดยไม่ต้องแก้ไขชั้นอื่น — ตัวอย่างเช่น เปลี่ยนจาก LinearLayoutManager เป็น GridLayoutManager โดยไม่ต้องเปลี่ยนโค้ดของ Adapter

คอมโพเนนต์ความรับผิดชอบการนำไปใช้
Adapterสร้าง ViewHolder, ผูกข้อมูลกับ View, แจ้งเตือนการเปลี่ยนแปลงRecyclerView.Adapter<VH>
ViewHolderแคชการอ้างอิง View, หลีกเลี่ยง findViewById()RecyclerView.ViewHolder
LayoutManagerกำหนดตำแหน่งรายการ, กำหนดทิศทางการเลื่อนLinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager
ItemAnimatorแอนิเมชันสำหรับการเพิ่ม, ลบ, ย้ายรายการDefaultItemAnimator
ItemDecorationวาดตัวแบ่ง, ระยะห่าง, พื้นหลังระหว่างรายการRecyclerView.ItemDecoration

วงจรการทำงาน: (1) Adapter สร้าง ViewHolder ผ่าน onCreateViewHolder(), (2) LayoutManager กำหนดตำแหน่งของ View ใหม่บนหน้าจอ, (3) Adapter ผูกข้อมูลผ่าน onBindViewHolder(), (4) เมื่อเลื่อน ViewHolder ที่ออกจากหน้าจอจะเข้าสู่พูล (RecycledViewPool) เพื่อนำกลับมาใช้ใหม่ แทนที่จะสร้าง View ใหม่ จะนำ View ที่มีอยู่กลับมาใช้ใหม่ — นี่คือกลไกประสิทธิภาพหลัก

การใช้งาน ViewHolder ใน RecyclerView

ViewHolder เป็นคลาสที่เก็บการอ้างอิงไปยัง View (TextView, ImageView ฯลฯ) ภายในรายการของลิสต์ หากไม่มี ViewHolder ทุกครั้งที่เลื่อนจะเรียก findViewById() — หนึ่งในการดำเนินการที่แพงที่สุดของ UI Android ViewHolder ขจัดการเรียกนี้โดยแคชการอ้างอิงหลังจากการผูกครั้งแรก

kotlin
// โมเดลข้อมูล
data class Article(
    title: String,
    summary: String,
    author: String,
    imageUrl: String?
)

// ViewHolder — เก็บการอ้างอิง View
class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val titleText = itemView.findViewById<TextView>(R.id.tvTitle)
    private val summaryText = itemView.findViewById<TextView>(R.id.tvSummary)
    private val authorText = itemView.findViewById<TextView>(R.id.tvAuthor)

    fun bind(article: Article) {
        titleText.text = article.title
        summaryText.text = article.summary
        authorText.text = article.author
    }
}

กฎปฏิบัติ: ทุก View ในเลย์เอาต์ของรายการควรประกาศเป็นคุณสมบัติของ ViewHolder ด้วย findViewById() เพียงครั้งเดียว — ในคอนสตรัคเตอร์ เมธอด bind() ไม่เรียก findViewById() แต่จะตั้งค่าข้อความ สี และตัวฟังเท่านั้น วิธีการนี้เร่งการเลื่อนรายการได้ 30–50% ตามข้อมูลของ Google (Android Performance Patterns, 2025)

ประเภทของ LayoutManager: การเลือกการจัดเรียงองค์ประกอบ

LayoutManager กำหนดว่ารายการถูกวางตำแหน่งภายใน RecyclerView อย่างไร Android มีการใช้งานเริ่มต้นสามแบบ: LinearLayoutManager, GridLayoutManager และ StaggeredGridLayoutManager การเลือก LayoutManager ส่งผลต่อการรับรู้ข้อมูลและประสิทธิภาพการเลื่อน

LayoutManagerการจัดเรียงเมื่อใดควรใช้วิธีการตั้งค่า
LinearLayoutManagerรายการ (แนวตั้งหรือแนวนอน)ฟีด, แชท, การแจ้งเตือน, รายการสินค้าLinearLayoutManager(context)
GridLayoutManagerกริด N คอลัมน์แกลเลอรี, แคตตาล็อก, ไอคอน, กริดรูปภาพGridLayoutManager(context, spanCount)
StaggeredGridLayoutManagerกริดซิกแซก (ความสูงรายการต่างกัน)บอร์ด Pinterest, โน้ต, แกลเลอรีแบบ masonryStaggeredGridLayoutManager(spanCount, orientation)
kotlin
// การตั้งค่า LinearLayoutManager ใน Fragment
class ArticleListFragment : Fragment() {
    private lateinit var binding: FragmentArticleListBinding

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val recyclerView = binding.recyclerView
        recyclerView.layoutManager = LinearLayoutManager(requireContext())
        recyclerView.adapter = ArticleAdapter(articlesList)

        // การเพิ่มประสิทธิภาพ: ขนาดคงที่ + พูล
        recyclerView.setHasFixedSize(true)
        recyclerView.setItemViewCacheSize(20)

        // ตัวแบ่งระหว่างรายการ
        val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
        recyclerView.addItemDecoration(divider)
    }
}

ประสิทธิภาพ: LinearLayoutManager ที่มีการเลื่อนแนวตั้งเป็นตัวเลือกที่เร็วที่สุดเพราะรายการถูกจัดเรียงตามลำดับและ LayoutManager คำนวณตำแหน่งใน O(1) GridLayoutManager ต้องการการคำนวณเพิ่มเติมสำหรับการแบ่งคอลัมน์แต่ยังคงมีประสิทธิภาพด้วย spanCount ที่คงที่ StaggeredGridLayoutManager ช้าที่สุดในสามประเภทเพราะต้องคำนวณตำแหน่งรายการในรูปแบบซิกแซกโดยพิจารณาความสูงของรายการข้างเคียง ใช้เฉพาะเมื่อต้องการความสูงของเซลล์ที่แตกต่างกันทางสายตา

Adapter และ DiffUtil: การอัปเดตข้อมูลที่มีประสิทธิภาพ

Adapter ใน RecyclerView นำรูปแบบ Adapter ของ GoF ไปใช้: มันแปลงข้อมูล (List<T>) เป็น ViewHolder ที่แสดงบนหน้าจอ เมื่อข้อมูลเปลี่ยน Adapter สามารถแจ้ง RecyclerView ผ่าน notifyDataSetChanged(), notifyItemInserted() และเมธอดที่คล้ายกัน ปัญหาคือ notifyDataSetChanged() วาดรายการที่มองเห็นทั้งหมดใหม่ ทำให้เกิดการกระตุก (jank)

kotlin
// Adapter ที่มี DiffUtil สำหรับการอัปเดตที่มีประสิทธิภาพ
class ArticleAdapter : RecyclerView.Adapter<ArticleViewHolder>() {

    private var articles: List<Article> = emptyList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_article, parent, false)
        return ArticleViewHolder(view)
    }

    override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
        holder.bind(articles[position])
    }

    override fun getItemCount(): Int = articles.size

    // การอัปเดตรายการผ่าน DiffUtil
    fun updateArticles(newArticles: List<Article>) {
        val diffCallback = ArticleDiffCallback(articles, newArticles)
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        articles = newArticles
        diffResult.dispatchUpdatesTo(this)
    }
}

// Callback สำหรับ DiffUtil
class ArticleDiffCallback(
    private val oldList: List<Article>,
    private val newList: List<Article>
) : DiffUtil.Callback() {

    override fun getOldListSize() = oldList.size
    override fun getNewListSize() = newList.size

    override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean {
        return oldList[oldPos].title == newList[newPos].title
    }

    override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean {
        return oldList[oldPos] == newList[newPos]
    }
}

DiffUtil ใช้อัลกอริธึม ความแตกต่างของ Eugene W. Myers ซึ่งคำนวณจำนวนการดำเนินการขั้นต่ำ (แทรก, ลบ, ย้าย, เปลี่ยน) เพื่อแปลงรายการเก่าเป็นรายการใหม่ สำหรับรายการ 100 รายการ DiffUtil ทำงานใน 1–5 มิลลิวินาที (Google, 2025) สำหรับรายการขนาดใหญ่ (10000+) ให้ใช้ AsyncListDiffer หรือ PagingDataAdapter จากไลบรารี Paging — พวกเขาคำนวณในเธรดพื้นหลัง

RecyclerView กับ ListView: การเปรียบเทียบ

ListView เป็นรุ่นก่อนของ RecyclerView เปิดตัวใน Android 1.0 (API 1) มันแสดงรายการได้เช่นกันแต่ไม่บังคับใช้ ViewHolder ไม่รองรับ LayoutManager และไม่สามารถเคลื่อนไหวการเปลี่ยนแปลงได้ RecyclerView ถูกออกแบบมาแทนที่ ListView ด้วยสถาปัตยกรรมที่เข้มงวดกว่าและประสิทธิภาพที่ดีกว่า

เกณฑ์RecyclerViewListView
ViewHolderบังคับ (สถาปัตยกรรม)แนะนำแต่ไม่บังคับ
LayoutManagerแยก: รายการ, กริด, ซิกแซกเฉพาะรายการแนวตั้ง
แอนิเมชันการเปลี่ยนแปลงDefaultItemAnimator ในตัวไม่มีการรองรับในตัว
การแจ้งเตือนการเปลี่ยนแปลงละเอียด: notifyItemInserted/Removedเฉพาะ notifyDataSetChanged() สำหรับทั้งรายการ
DiffUtilรองรับผ่าน DiffUtil.Callbackไม่มีสิ่งที่เทียบเท่า
ตัวแบ่งItemDecoration (กำหนดเอง)android:divider (ในตัว)
เวอร์ชันขั้นต่ำAPI 14 (Android 4.0) ผ่าน AndroidXAPI 1 (ทุกเวอร์ชัน)

คำแนะนำของ Google (Android Developers, 2026): ใช้ RecyclerView สำหรับโปรเจกต์ใหม่ทั้งหมด ListView สามารถคงอยู่ในโค้ดเบสเก่าที่การย้ายถิ่นไม่คุ้มค่า RecyclerView ให้ประสิทธิภาพที่ดีกว่าบน 100+ รายการ รองรับการเลื่อนแนวนอนและกริดโดยไม่ต้องมีวิธีแก้ไขเพิ่มเติม ใน Android 15 ListView ถูกทำเครื่องหมายอย่างเป็นทางการว่าล้าสมัยบางส่วน

คำถามที่พบบ่อย

RecyclerView ไม่แสดงรายการ — จะทำอย่างไร?

ตรวจสอบสามเงื่อนไข: (1) Adapter ถูกตั้งค่าผ่าน recyclerView.adapter = adapter, (2) LayoutManager ถูกตั้งค่าผ่าน recyclerView.layoutManager = LinearLayoutManager(context), (3) รายการข้อมูลไม่ว่างและ adapter ได้รับการแจ้งเตือนแล้ว (notifyDataSetChanged()) ข้อผิดพลาดทั่วไปคือการตั้งค่าข้อมูลหลังจากเรียก notifyDataSetChanged() ข้อมูลควรถูกกำหนดก่อนการแจ้งเตือน ตรวจสอบขนาดรายการ: adapter.itemCount ต้องมากกว่า 0

ทำไม RecyclerView ถึงเลื่อนช้า?

ความช้า ขณะเลื่อน (jank) เกิดขึ้นเมื่อ onBindViewHolder() ดำเนินการหนัก: โหลดรูปภาพโดยไม่แคช, findViewById() ภายใน bind, การคำนวณซับซ้อน วิธีแก้: (1) ใช้ Glide หรือ Coil สำหรับโหลดรูปภาพแบบอะซิงโครนัส, (2) ย้ายการเรียก findViewById() ทั้งหมดไปยังคอนสตรัคเตอร์ของ ViewHolder, (3) สำหรับการคำนวณความแตกต่าง ให้ใช้ AsyncListDiffer เปิดการสร้างโปรไฟล์ GPU ใน Android Studio (Profile GPU Rendering) เพื่อค้นหาเฟรมที่ช้า

วิธีสร้าง RecyclerView แนวนอน?

ส่งการวางแนวไปยัง LayoutManager: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) พารามิเตอร์ที่สองคือ reverseLayout (false = ซ้ายไปขวา) สำหรับกริดแนวนอน ให้ใช้ GridLayoutManager ที่มีการวางแนวแนวนอนหรือ LinearSnapHelper ที่กำหนดเองสำหรับการเลื่อนแบบหน้า รายการแนวนอนเหมาะสำหรับม้าหมุนสินค้า รูปภาพ หมวดหมู่

วิธีเพิ่ม click listener ให้กับรายการ RecyclerView?

RecyclerView ไม่มี onClickListener ในตัว (ต่างจาก ListView ที่มี onItemClickListener) นำไปใช้ใน ViewHolder: ส่งแลมบ์ดาไปยังคอนสตรัคเตอร์และตั้งค่า itemView.setOnClickListener ตัวอย่าง: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView) เรียก onItemClick(article) ภายใน bind() อีกทางเลือกคือใช้ RecyclerView.addOnItemTouchListener() สำหรับการจัดการท่าทาง

RecycledViewPool คืออะไรและกำหนดค่าอย่างไร?

RecycledViewPool คือพูลภายในของ ViewHolder ที่มองไม่เห็นเมื่อเลื่อน แทนที่จะถูกทำลาย พวกมันถูกเก็บในพูลและนำกลับมาใช้ใหม่ โดยค่าเริ่มต้น พูลเก็บ 5 ViewHolder ต่อประเภท เพิ่มขนาดสำหรับเลย์เอาต์ที่ซับซ้อน: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount) ถ้า RecyclerView มีหลายประเภท View (viewType) พูลจะเก็บสแต็กแยกสำหรับแต่ละประเภท การแชร์ RecycledViewPool ระหว่าง RecyclerView ต่างๆ ช่วยประหยัดหน่วยความจำในหน้าจอที่มีรายการซ้อนกัน

สรุป

  • RecyclerView เป็นคอมโพเนนต์ Android Jetpack ที่ทันสมัยสำหรับรายการและกริดด้วยประสิทธิภาพสูงสุด 60 FPS
  • ViewHolder เป็นรูปแบบบังคับสำหรับแคช View ซึ่งกำจัด findViewById() ทุกครั้งที่เลื่อน
  • Adapter จัดการข้อมูลและสร้าง ViewHolder ผ่าน onCreateViewHolder และ onBindViewHolder
  • LayoutManager — สามการนำไปใช้: LinearLayoutManager (รายการ), GridLayoutManager (กริด), StaggeredGridLayoutManager (ซิกแซก)
  • DiffUtil — อัลกอริธึมสำหรับการอัปเดตรายการน้อยที่สุด: การวาดซ้ำแบบละเอียดแทนการรีเฟรชทั้งหมด
  • RecyclerView ถูกใช้ใน 78% ของแอป Android ใน 100 อันดับแรกและ Google แนะนำอย่างเป็นทางการให้ใช้แทน ListView
  • ประสิทธิภาพของ RecyclerView ทำได้ผ่านการรวม ViewHolder, การแจ้งเตือนแบบละเอียด และการคำนวณความแตกต่างแบบอะซิงโครนัส

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม