RecyclerView — Android Jetpack komponenti, böyük veri dəstlərini siyahı və şəbəkə şəklində səmərəli göstərmək üçün. ListView-dən fərqli olaraq, RecyclerView ViewHolder-ları təkrar istifadə edir və düzəni LayoutManager vasitəsilə idarə edir. Google (Android Developers, 2026) məlumatına görə, RecyclerView 1000+ elementli siyahını skroll edərkən ViewHolder pulu və DiffUtil fərq alqoritmi sayəsində saniyədə 60 kadr emal edir. Android proqramlarının memarlığı haqqında daha ətraflı ListView haqqında məqaləmizdə oxuyun.
Əsas
RecyclerView — Android Support Library v7-nin bir hissəsi olaraq Google I/O 2014-də təqdim edilən Android Jetpack kitabxanasının komponentidir. Dinamik siyahı və şəbəkələri yüksək performansla göstərmək üçün nəzərdə tutulub. RecyclerView ListView-in əvəzi olaraq ortaya çıxdı və sələfinin əsas problemini — ViewHolder-ların məcburi təkrar istifadəsinin olmamasını həll edir.
RecyclerView memarlığı Model-View-Adapter nümunəsi üzərində qurulub: verilənlər modeldə (List, LiveData, Flow) saxlanılır, göstərilməni Adapter idarə edir, düzəni isə LayoutManager nəzarət edir. Hər bir komponent öz məsuliyyət zonasına cavabdehdir, bu da sistemi çevik və genişləndirilə bilən edir.
Android Developers (2025) sorğusuna görə, RecyclerView Google Play top-100-dən 78% Android proqramlarında istifadə olunur. 1000+ elementli siyahının skroll performansı orta seqment cihazlarda üç mexanizm sayəsində 60 FPS-də sabit qalır: ViewHolder pulu, yeniləmələrin fərq hesablanması və asinxron veri yükləmə.
RecyclerView aşağıdakılar üçün optimaldır: naməlum sayda elementli siyahılar (lentlər, söhbətlər, loglar), N sütunlu şəbəkələr (qalereyalar, kataloqlar), kaskad düzenlər (Pinterest lövhələri), elementlərin əlavə edilməsi/silinməsi animasiyası olan siyahılar. 2–5 elementli sadə ekranlar üçün LinearLayout və ya ScrollView daha sadə və səmərəlidir — RecyclerView əlavə yük gətirir.
RecyclerView istifadə etmək üçün build.gradle (app)-ə asıllıq əlavə edin: implementation 'androidx.recyclerview:recyclerview:1.4.0'. Minimum API versiyası — 14 (Android 4.0). AndroidX RecyclerView 1.3.0-dan başlayaraq, element seçimi üçün recyclerview-selection və sürüşdürmə üçün recyclerview-swipe modulları mövcuddur.
RecyclerView üç müstəqil təbəqəyə bölünür: Adapter verilənlər və ViewHolder-ları idarə edir, LayoutManager elementlərin yerləşdirilməsinə cavabdehdir, ItemAnimator animasiyaları idarə edir. Belə memarlıq, digərlərini dəyişmədən istənilən təbəqəni əvəz etməyə imkan verir — məsələn, Adapter kodunu dəyişmədən LinearLayoutManager-dən GridLayoutManager-ə keçmək.
| Komponent | Vəzifələri | Tətbiqi |
|---|---|---|
| Adapter | ViewHolder-ların yaradılması, verilənlərin View-ə bağlanması, dəyişikliklər barədə xəbərdarlıq | RecyclerView.Adapter<VH> |
| ViewHolder | View istinadlarının keşlənməsi, findViewById()-dən qaçınma | RecyclerView.ViewHolder |
| LayoutManager | Elementlərin yerləşdirilməsi, skroll istiqamətinin təyini | LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager |
| ItemAnimator | Elementlərin əlavə edilməsi, silinməsi, daşınması animasiyası | DefaultItemAnimator |
| ItemDecoration | Elementlər arasında ayırıcıların, boşluqların, fonların çəkilməsi | RecyclerView.ItemDecoration |
İş dövrü: (1) Adapter onCreateViewHolder() vasitəsilə ViewHolder yaradır, (2) LayoutManager ekranda yeni View-in mövqeyini təyin edir, (3) Adapter onBindViewHolder() vasitəsilə verilənləri bağlayır, (4) skroll zamanı ekrandan çıxan ViewHolder-lar təkrar istifadə üçün hovuza (RecycledViewPool) daxil olur. Yeni View yaratmaq əvəzinə mövcud olanlar təkrar istifadə olunur — bu əsas performans mexanizmidir.
ViewHolder — siyahı elementi daxilində View-lərə (TextView, ImageView və s.) istinadları saxlayan sinifdir. ViewHolder olmadan hər skroll zamanı sistem findViewById() — Android UI-nin ən bahalı əməliyyatlarından birini çağırardı. ViewHolder ilk bağlanmadan sonra istinadları yadda saxlayaraq bu çağırışı aradan qaldırır.
// Veri modeli
data class Article(
title: String,
summary: String,
author: String,
imageUrl: String?
)
// ViewHolder — View-ə istinadları saxlayır
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
}
}
Praktiki qayda: element düzenindəki hər View ViewHolderin xassəsi kimi findViewById() ilə dəqiq bir dəfə — konstruktorda elan edilməlidir. bind() metodu findViewById() çağırmır, yalnız mətn, rənglər və dinləyicilər təyin edir. Bu yanaşma Google (Android Performance Patterns, 2025) məlumatına görə siyahı skrollunu 30–50% sürətləndirir.
LayoutManager elementlərin RecyclerView daxilində necə yerləşdiyini təyin edir. Android standart olaraq üç tətbiq təqdim edir: LinearLayoutManager, GridLayoutManager və StaggeredGridLayoutManager. LayoutManager seçimi istifadəçinin verilənləri qavramasına və skroll performansına təsir edir.
| LayoutManager | Yerləşmə | Nə vaxt istifadə edilməli | Qurma metodu |
|---|---|---|---|
| LinearLayoutManager | Siyahı (şaquli və ya üfüqi) | Lentlər, söhbətlər, bildirişlər, məhsul siyahıları | LinearLayoutManager(context) |
| GridLayoutManager | N sütunlu şəbəkə | Qalereyalar, kataloqlar, ikonlar, şəkil şəbəkəsi | GridLayoutManager(context, spanCount) |
| StaggeredGridLayoutManager | Kaskad şəbəkə (müxtəlif hündürlükdə elementlər) | Pinterest lövhələri, qeydlər, masonry qalereyaları | StaggeredGridLayoutManager(spanCount, orientation) |
// LinearLayoutManager-in Fragment-də qurulması
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)
// Optimizasiya: sabit ölçü + hovuz
recyclerView.setHasFixedSize(true)
recyclerView.setItemViewCacheSize(20)
// Elementlər arasında ayırıcı
val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
recyclerView.addItemDecoration(divider)
}
}
Performans: şaquli skroll ilə LinearLayoutManager ən sürətli variantdır, çünki elementlər ardıcıl yerləşir və LayoutManager mövqeləri O(1) ilə hesablayır. GridLayoutManager sütunlara bölmək üçün əlavə hesablamalar tələb edir, lakin sabit spanCount ilə səmərəli qalır. StaggeredGridLayoutManager üçü arasında ən yavaşdır, çünki qonşu elementlərin hündürlüyünü nəzərə alaraq kaskaddakı elementin mövqeyini hesablamalıdır. Yalnız hüceyrələrin müxtəlif hündürlüyü vizual olaraq tələb olunduqda istifadə edin.
Adapter RecyclerView-də GoF-dan Adapter nümunəsini tətbiq edir: verilənləri (List<T>) ekranda göstərilən ViewHolder-lara çevirir. Verilənlər dəyişdikdə Adapter RecyclerView-ə notifyDataSetChanged(), notifyItemInserted() və analoji metodlar vasitəsilə xəbər verə bilər. Problem ondadır ki, notifyDataSetChanged() bütün görünən elementləri təkrar çəkir, bu da əyilmələrə (jank) səbəb olur.
// DiffUtil ilə səmərəli yeniləmə üçün Adapter
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
// Siyahının DiffUtil vasitəsilə yenilənməsi
fun updateArticles(newArticles: List<Article>) {
val diffCallback = ArticleDiffCallback(articles, newArticles)
val diffResult = DiffUtil.calculateDiff(diffCallback)
articles = newArticles
diffResult.dispatchUpdatesTo(this)
}
}
// DiffUtil üçün Callback
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 köhnə siyahını yenisinə çevirmək üçün minimum əməliyyat sayını (insert, remove, move, change) hesablayan Eugene W. Myers fərq alqoritmindən istifadə edir. 100 elementli siyahı üçün DiffUtil 1–5 ms ərzində işləyir (Google, 2025). Böyük siyahılar (10000+) üçün AsyncListDiffer və ya Paging kitabxanasından PagingDataAdapter istifadə edin — onlar hesablamaları fon thread-də aparır.
ListView — Android 1.0 (API 1)-də ortaya çıxan RecyclerView-in sələfidir. O da siyahıları göstərir, lakin ViewHolder-i məcbur etmir, LayoutManager-i dəstəkləmir və dəyişiklikləri animasiya edə bilmir. RecyclerView daha sərt memarlıq və performans ilə ListView-in əvəzi olaraq hazırlanmışdır.
| Meyar | RecyclerView | ListView |
|---|---|---|
| ViewHolder | Məcburi (memarlıq) | Tövsiyə olunur, lakin məcburi deyil |
| LayoutManager | Bölgü: siyahı, şəbəkə, kaskad | Yalnız şaquli siyahı |
| Dəyişiklik animasiyası | DefaultItemAnimator daxili | Daxili dəstək yoxdur |
| Dəyişiklik bildirişi | Nöqtəvi: notifyItemInserted/Removed | notifyDataSetChanged() yalnız bütün siyahı |
| DiffUtil | DiffUtil.Callback vasitəsilə dəstək | Ekvivalenti yoxdur |
| Ayırıcılar | ItemDecoration (fərdi) | android:divider (daxili) |
| Minimum versiya | API 14 (Android 4.0) AndroidX ilə | API 1 (bütün versiyalar) |
Google tövsiyəsi (Android Developers, 2026): bütün yeni layihələr üçün RecyclerView istifadə edin. ListView köhnə kod bazalarında (legacy) buraxıla bilər, burada miqrasiya xərcləri ödəmir. RecyclerView 100+ elementdə daha yaxşı performans təmin edir, üfüqi skroll və şəbəkələri əlavə vasitələr olmadan dəstəkləyir. Android 15-də ListView rəsmi olaraq qismən köhnəlmiş kimi qeyd edilmişdir.
Tez-tez verilən suallar
Üç şərti yoxlayın: (1) Adapter recyclerView.adapter = adapter vasitəsilə qurulub, (2) LayoutManager recyclerView.layoutManager = LinearLayoutManager(context) vasitəsilə qurulub, (3) siyahıdakı verilənlər boş deyil və adapter xəbərdar edilib (notifyDataSetChanged()). Tipik səhv — notifyDataSetChanged() çağırışından sonra verilənlərin təyin edilməsi. Verilənlər bildirişdən əvvəl təyin edilməlidir. Siyahı ölçüsünü yoxlayın: adapter.itemCount 0-dan böyük olmalıdır.
Ləngimələr skroll zamanı (jank) onBindViewHolder() ağır əməliyyatlar yerinə yetirdikdə yaranır: keşləmə olmadan şəkillərin yüklənməsi, bind daxilində findViewById(), mürəkkəb hesablamalar. Həll yolları: (1) asinxron şəkil yükləmə üçün Glide və ya Coil kitabxanasından istifadə edin, (2) bütün findViewById()-ləri ViewHolder konstruktoruna çıxarın, (3) fərq hesablamaları üçün AsyncListDiffer istifadə edin. Yavaş kadrları tapmaq üçün Android Studio-da GPU profilini (Profile GPU Rendering) aktiv edin.
LayoutManager-ə oriyentasiya ötürün: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). İkinci parametr reverseLayout-dir (false = soldan sağa). Üfüqi şəbəkə üçün üfüqi oriyentasiya ilə GridLayoutManager və ya səhifələmə skrollu üçün fərdi LinearSnapHelper istifadə edin. Üfüqi siyahılar məhsul karuselləri, şəkillər, kateqoriyalar üçün yaxşı uyğun gəlir.
RecyclerView-də daxili onClickListener yoxdur (ListView-də onItemClickListener-dən fərqli olaraq). Onu ViewHolder-də tətbiq edin: konstruktora lambda ötürün və itemView.setOnClickListener təyin edin. Nümunə: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). bind() daxilində onItemClick(article) çağırın. Alternativ — jestləri idarə etmək üçün RecyclerView.addOnItemTouchListener() təyin edin.
RecycledViewPool — skroll zamanı görünməz olan ViewHolder-ların daxili hovuzudur. Məhv edilmək əvəzinə hovuzda saxlanılır və təkrar istifadə olunur. Standart olaraq hovuz hər növdən 5 ViewHolder saxlayır. Mürəkkəb düzenlər üçün ölçüsü artırın: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). RecyclerView-də bir neçə View növü (viewType) varsa, hovuz hər biri üçün ayrı-ayrı yığınlar saxlayır. RecycledViewPool-un müxtəlif RecyclerView-lər arasında birgə istifadəsi iç-içə siyahıları olan ekranlarda yaddaşa qənaət edir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun