RecyclerView, büyük veri kümelerini listeler ve ızgaralar halinde verimli bir şekilde görüntülemek için bir Android Jetpack bileşenidir. ListView'ın aksine RecyclerView, ViewHolder'ları yeniden kullanır ve düzeni LayoutManager aracılığıyla yönetir. Google'a göre (Android Developers, 2026), RecyclerView, ViewHolder havuzlaması ve DiffUtil fark algoritması sayesinde 1000+ öğeli bir listeyi kaydırırken saniyede 60 kareye kadar işlem yapar. Android uygulama mimarisi hakkında daha fazla bilgi için ListView hakkındaki makalemize göz atın.
Önemli Noktalar
RecyclerView, Google I/O 2014'te Android Support Library v7'nin bir parçası olarak tanıtılan Android Jetpack kütüphanesinin bir bileşenidir. Dinamik listeleri ve ızgaraları yüksek performansla görüntülemek için tasarlanmıştır. RecyclerView, ListView'ın yerine geçecek şekilde ortaya çıkmış ve selefinin temel sorununu — zorunlu ViewHolder yeniden kullanımının olmamasını — çözmüştür.
RecyclerView mimarisi Model-View-Adapter deseni üzerine kurulmuştur: veriler bir modelde (List, LiveData, Flow) saklanır, işleme Adapter tarafından yönetilir ve düzen LayoutManager tarafından kontrol edilir. Her bileşen kendi alanından sorumludur ve bu da sistemi esnek ve genişletilebilir kılar.
Android Developers anketine (2025) göre, Google Play ilk 100'deki Android uygulamalarının %78'inde RecyclerView kullanılmaktadır. 1000+ öğeli bir liste için kaydırma performansı, üç mekanizma sayesinde orta sınıf cihazlarda 60 FPS'de sabit kalır: ViewHolder havuzlama, fark tabanlı güncelleme hesaplaması ve eşzamansız veri yükleme.
RecyclerView şunlar için idealdir: bilinmeyen sayıda öğe içeren listeler (feed'ler, sohbetler, günlükler), N sütunlu ızgaralar (galeriler, kataloglar), kademeli düzenler (Pinterest panoları) ve ekleme/kaldırma animasyonları olan listeler. 2–5 öğeli basit ekranlar için LinearLayout veya ScrollView daha basit ve verimlidir — RecyclerView ek yük getirir.
RecyclerView'ı kullanmak için build.gradle (app)'e bağımlılığı ekleyin: implementation 'androidx.recyclerview:recyclerview:1.4.0'. Minimum API sürümü 14'tür (Android 4.0). AndroidX RecyclerView 1.3.0'dan itibaren, öğe seçimi için recyclerview-selection ve kaydırma hareketleri için recyclerview-swipe modülleri mevcuttur.
RecyclerView üç bağımsız katmana ayrılmıştır: Adapter verileri ve ViewHolder'ları yönetir, LayoutManager öğelerin konumlandırılmasıyla ilgilenir ve ItemAnimator animasyonları kontrol eder. Bu mimari, diğerlerini değiştirmeden herhangi bir katmanın değiştirilmesine olanak tanır — örneğin, Adapter kodunu değiştirmeden LinearLayoutManager'dan GridLayoutManager'a geçmek.
| Bileşen | Sorumluluklar | Uygulama |
|---|---|---|
| Adapter | ViewHolder oluşturma, verileri View'a bağlama, değişiklikleri bildirme | RecyclerView.Adapter<VH> |
| ViewHolder | View referanslarını önbelleğe alma, findViewById()'den kaçınma | RecyclerView.ViewHolder |
| LayoutManager | Öğeleri konumlandırma, kaydırma yönünü belirleme | LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager |
| ItemAnimator | Öğe ekleme, kaldırma, taşıma animasyonu | DefaultItemAnimator |
| ItemDecoration | Öğeler arasında ayırıcılar, boşluklar, arka planlar çizme | RecyclerView.ItemDecoration |
Çalışma döngüsü: (1) Adapter, onCreateViewHolder() aracılığıyla bir ViewHolder oluşturur, (2) LayoutManager, ekranda yeni View'ın konumunu belirler, (3) Adapter, onBindViewHolder() aracılığıyla verileri bağlar, (4) kaydırma sırasında ekrandan çıkan ViewHolder'lar yeniden kullanım için havuza (RecycledViewPool) girer. Yeni View'lar oluşturmak yerine mevcut olanlar yeniden kullanılır — bu temel performans mekanizmasıdır.
ViewHolder, bir liste öğesi içindeki View'lara (TextView, ImageView, vb.) referansları saklayan bir sınıftır. ViewHolder olmadan, her kaydırma findViewById()'i tetikler — Android arayüzünün en pahalı işlemlerinden biri. ViewHolder, ilk bağlamadan sonra referansları önbelleğe alarak bu çağrıyı ortadan kaldırır.
// Veri modeli
data class Article(
title: String,
summary: String,
author: String,
imageUrl: String?
)
// ViewHolder — View referanslarını saklar
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
}
}
Pratik kural: öğe düzenindeki her View, findViewById() ile tam olarak bir kez — kurucuda — ViewHolder özelliği olarak bildirilmelidir. bind() yöntemi findViewById() çağırmaz, yalnızca metin, renkler ve dinleyiciler ayarlar. Bu yaklaşım, Google'a göre (Android Performance Patterns, 2025) liste kaydırmayı %30–50 hızlandırır.
LayoutManager, öğelerin RecyclerView içinde nasıl konumlandırılacağını tanımlar. Android üç varsayılan uygulama sağlar: LinearLayoutManager, GridLayoutManager ve StaggeredGridLayoutManager. LayoutManager seçimi, veri algısını ve kaydırma performansını etkiler.
| LayoutManager | Yerleşim | Ne zaman kullanılır | Kurulum yöntemi |
|---|---|---|---|
| LinearLayoutManager | Liste (dikey veya yatay) | Feed'ler, sohbetler, bildirimler, ürün listeleri | LinearLayoutManager(context) |
| GridLayoutManager | N sütunlu ızgara | Galeriler, kataloglar, simgeler, görüntü ızgaraları | GridLayoutManager(context, spanCount) |
| StaggeredGridLayoutManager | Kademeli ızgara (farklı öğe yükseklikleri) | Pinterest panoları, notlar, masonry galerileri | StaggeredGridLayoutManager(spanCount, orientation) |
// Fragment'te LinearLayoutManager ayarlama
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)
// Optimizasyon: sabit boyut + havuz
recyclerView.setHasFixedSize(true)
recyclerView.setItemViewCacheSize(20)
// Öğeler arasında ayırıcı
val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
recyclerView.addItemDecoration(divider)
}
}
Performans: Dikey kaydırmalı LinearLayoutManager en hızlı seçenektir çünkü öğeler sırayla yerleştirilir ve LayoutManager O(1)'de konumları hesaplar. GridLayoutManager, sütun bölme için ek hesaplamalar gerektirir ancak sabit spanCount ile verimli kalır. StaggeredGridLayoutManager üçü arasında en yavaş olanıdır çünkü komşu öğelerin yüksekliklerini dikkate alarak kademede öğe konumlarını hesaplaması gerekir. Yalnızca görsel olarak farklı hücre yükseklikleri gerektiğinde kullanın.
Adapter, RecyclerView'da GoF Adapter desenini uygular: verileri (List<T>) ekranda görüntülenen ViewHolder'lara dönüştürür. Veriler değiştiğinde, Adapter notifyDataSetChanged(), notifyItemInserted() ve benzer yöntemlerle RecyclerView'ı bilgilendirebilir. Sorun, notifyDataSetChanged()'in tüm görünür öğeleri yeniden çizmesi ve takılmalara (jank) neden olmasıdır.
// Verimli güncellemeler için DiffUtil ile 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
// DiffUtil ile listeyi güncelleme
fun updateArticles(newArticles: List<Article>) {
val diffCallback = ArticleDiffCallback(articles, newArticles)
val diffResult = DiffUtil.calculateDiff(diffCallback)
articles = newArticles
diffResult.dispatchUpdatesTo(this)
}
}
// DiffUtil için 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, eski listeyi yeni listeye dönüştürmek için minimum işlem sayısını (ekle, kaldır, taşı, değiştir) hesaplayan Eugene W. Myers fark algoritmasını kullanır. 100 öğeli bir liste için DiffUtil 1–5 ms içinde çalışır (Google, 2025). Büyük listeler (10000+) için Paging kütüphanesinden AsyncListDiffer veya PagingDataAdapter kullanın — hesaplamaları arka plan iş parçacığında gerçekleştirirler.
ListView, RecyclerView'ın öncülüdür ve Android 1.0'da (API 1) tanıtılmıştır. Ayrıca listeleri görüntüler ancak ViewHolder'ı zorunlu kılmaz, LayoutManager'ı desteklemez ve değişiklikleri canlandıramaz. RecyclerView, daha katı bir mimari ve daha iyi performansla ListView'ın yerini alacak şekilde tasarlanmıştır.
| Kriter | RecyclerView | ListView |
|---|---|---|
| ViewHolder | Zorunlu (mimari) | Önerilir ancak zorunlu değil |
| LayoutManager | Ayrım: liste, ızgara, kademeli | Yalnızca dikey liste |
| Değişiklik animasyonu | DefaultItemAnimator yerleşik | Yerleşik destek yok |
| Değişiklik bildirimi | Ayrıntılı: notifyItemInserted/Removed | Yalnızca tüm liste için notifyDataSetChanged() |
| DiffUtil | DiffUtil.Callback aracılığıyla destek | Eşdeğeri yok |
| Ayırıcılar | ItemDecoration (özel) | android:divider (yerleşik) |
| Minimum sürüm | AndroidX aracılığıyla API 14 (Android 4.0) | API 1 (tüm sürümler) |
Google önerisi (Android Developers, 2026): tüm yeni projeler için RecyclerView kullanın. ListView, geçiş maliyetinin haklı olmadığı eski kod tabanlarında kalabilir. RecyclerView, 100+ öğede daha iyi performans sunar, ek geçici çözümler olmadan yatay kaydırmayı ve ızgaraları destekler. Android 15'te ListView resmi olarak kısmen kullanımdan kaldırılmış olarak işaretlenmiştir.
Sıkça Sorulan Sorular
Üç koşulu kontrol edin: (1) Adapter recyclerView.adapter = adapter ile ayarlandı mı, (2) LayoutManager recyclerView.layoutManager = LinearLayoutManager(context) ile ayarlandı mı, (3) veri listesi boş değil ve adapter bilgilendirildi mi (notifyDataSetChanged()). Tipik bir hata, notifyDataSetChanged() çağrıldıktan sonra veri ayarlamaktır. Veriler bildirimden önce atanmalıdır. Liste boyutunu kontrol edin: adapter.itemCount 0'dan büyük olmalıdır.
Kaydırma sırasındaki yavaşlık (jank), onBindViewHolder() ağır işlemler yaptığında oluşur: önbelleksiz resim yükleme, bind içinde findViewById(), karmaşık hesaplamalar. Çözümler: (1) eşzamansız resim yükleme için Glide veya Coil kullanın, (2) tüm findViewById() çağrılarını ViewHolder kurucusuna taşıyın, (3) fark hesaplamaları için AsyncListDiffer kullanın. Yavaş kareleri bulmak için Android Studio'da GPU Profil Oluşturma'yı (Profile GPU Rendering) etkinleştirin.
LayoutManager'a yönü iletin: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). İkinci parametre reverseLayout'dur (false = soldan sağa). Yatay bir ızgara için yatay yönlendirmeli GridLayoutManager veya sayfalı kaydırma için özel LinearSnapHelper kullanın. Yatay listeler, ürün, resim ve kategori karuselleri için uygundur.
RecyclerView'ın (onItemClickListener'a sahip ListView'ın aksine) yerleşik bir onClickListener'ı yoktur. Bunu ViewHolder'da uygulayın: kurucuya bir lambda iletin ve itemView.setOnClickListener ayarlayın. Örnek: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). bind() içinde onItemClick(article) çağrısı yapın. Alternatif olarak, jest işleme için RecyclerView.addOnItemTouchListener() kullanın.
RecycledViewPool, kaydırma sırasında görünmez hale gelen ViewHolder'ların dahili bir havuzudur. Yok edilmek yerine havuzda tutulur ve yeniden kullanılır. Varsayılan olarak havuz, her türden 5 ViewHolder depolar. Karmaşık düzenler için boyutu artırın: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Bir RecyclerView'da birden çok View türü (viewType) varsa, havuz her biri için ayrı yığınlar tutar. Farklı RecyclerView'lar arasında RecycledViewPool paylaşmak, iç içe listeler içeren ekranlarda bellek tasarrufu sağlar.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun