RecyclerView — چیست، ViewHolder و Adapter در Android

نویسنده: IT Sectr منتشر شده: 2026-02-23 زمان مطالعه: 8 دقیقه

RecyclerView — مؤلفه Android Jetpack برای نمایش کارآمد مجموعه‌های بزرگ داده به صورت لیست و شبکه. برخلاف ListView، RecyclerView ViewHolderها را بازیافت می‌کند و چیدمان را از طریق LayoutManager مدیریت می‌کند. طبق گفته Google (Android Developers, 2026)، RecyclerView هنگام اسکرول لیست 1000+ عنصر به لطف استخر ViewHolderها و الگوریتم تفاوت DiffUtil تا 60 فریم در ثانیه پردازش می‌کند. درباره معماری برنامه‌های 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() — یکی از گران‌ترین عملیات Android UI — را فراخوانی می‌کرد. 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() را فراخوانی نمی‌کند، فقط متن، رنگ‌ها و شنوندگان را تنظیم می‌کند. این رویکرد طبق Google (Android Performance Patterns, 2025) اسکرول لیست را 30-50% تسریع می‌کند.

انواع 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 difference algorithm استفاده می‌کند که حداقل تعداد عملیات (insert, remove, move, change) برای تبدیل لیست قدیم به جدید را محاسبه می‌کند. برای لیست 100 عنصری DiffUtil در 1-5 ms کار می‌کند (Google, 2025). برای لیست‌های بزرگ (10000+) از AsyncListDiffer یا PagingDataAdapter از کتابخانه Paging استفاده کنید — آنها محاسبات را در پس‌زمینه انجام می‌دهند.

مقایسه RecyclerView vs ListView

ListView — سلف RecyclerView، در Android 1.0 (API 1) ظاهر شد. آن نیز لیست‌ها را نمایش می‌دهد، اما ViewHolder را اجباری نمی‌کند، LayoutManager را پشتیبانی نمی‌کند و نمی‌تواند تغییرات را انیمیشن کند. RecyclerView به عنوان جایگزین ListView با معماری سخت‌گیرانه‌تر و عملکرد بالاتر طراحی شده است.

معیارRecyclerViewListView
ViewHolderاجباری (معماری)توصیه می‌شود اما اجباری نیست
LayoutManagerتقسیم: لیست، شبکه، آبشاریفقط لیست عمودی
انیمیشن تغییراتDefaultItemAnimator داخلیپشتیبانی داخلی ندارد
اعلان تغییراتنقطه‌ای: notifyItemInserted/RemovednotifyDataSetChanged() فقط کل لیست
DiffUtilپشتیبانی از طریق DiffUtil.Callbackمعادلی ندارد
جداکننده‌هاItemDecoration (سفارشی)android:divider (داخلی)
حداقل نسخهAPI 14 (Android 4.0) از طریق AndroidXAPI 1 (همه نسخه‌ها)

توصیه Google (Android Developers, 2026): برای همه پروژه‌های جدید از RecyclerView استفاده کنید. ListView را می‌توان در پایگاه‌های کد قدیمی (legacy) نگه داشت جایی که مهاجرت توجیه‌پذیر نیست. 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 پیاده‌سازی کنید: lambda را به سازنده منتقل کنید و itemView.setOnClickListener را تنظیم کنید. مثال: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). درون bind() onItemClick(article) را فراخوانی کنید. جایگزین — 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 از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید