RecyclerView হল Android Jetpack-এর একটি উপাদান যা তালিকা এবং গ্রিড আকারে বড় ডেটা সেট কার্যকরভাবে প্রদর্শনের জন্য। ListView-এর বিপরীতে, RecyclerView ViewHolder-গুলি পুনঃব্যবহার করে এবং LayoutManager-এর মাধ্যমে লেআউট পরিচালনা করে। Google-এর মতে (Android Developers, 2026), RecyclerView ViewHolder পুলিং এবং DiffUtil ডিফ অ্যালগরিদমের কারণে 1000+ আইটেমের তালিকা স্ক্রোল করার সময় প্রতি সেকেন্ডে 60 ফ্রেম পর্যন্ত প্রক্রিয়া করে। Android অ্যাপ আর্কিটেকচার সম্পর্কে আরও জানতে ListView-এর উপর আমাদের নিবন্ধটি পড়ুন।
মূল পয়েন্ট
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) অনুসারে, Google Play-এর শীর্ষ 100-এর মধ্যে 78% Android অ্যাপে RecyclerView ব্যবহৃত হয়। 1000+ আইটেমের তালিকার জন্য স্ক্রোলিং কর্মক্ষমতা তিনটি প্রক্রিয়ার কারণে মিড-রেঞ্জ ডিভাইসে 60 FPS-এ স্থিতিশীল থাকে: ViewHolder পুলিং, ডিফ-ভিত্তিক আপডেট গণনা এবং অ্যাসিঙ্ক্রোনাস ডেটা লোডিং।
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 তিনটি স্বাধীন স্তরে বিভক্ত: Adapter ডেটা এবং ViewHolder-গুলি পরিচালনা করে, LayoutManager আইটেম অবস্থান নির্ধারণ করে এবং ItemAnimator অ্যানিমেশন নিয়ন্ত্রণ করে। এই আর্কিটেকচার অন্যগুলি পরিবর্তন না করেই যেকোনো স্তর প্রতিস্থাপনের অনুমতি দেয় — উদাহরণস্বরূপ, Adapter কোড পরিবর্তন না করে LinearLayoutManager থেকে GridLayoutManager-এ সুইচ করা।
| উপাদান | দায়িত্ব | বাস্তবায়ন |
|---|---|---|
| Adapter | ViewHolder তৈরি, ডেটা View-এ বাইন্ড করা, পরিবর্তন সম্পর্কে বিজ্ঞপ্তি | RecyclerView.Adapter<VH> |
| ViewHolder | View রেফারেন্স ক্যাশ করা, findViewById() এড়ানো | RecyclerView.ViewHolder |
| LayoutManager | আইটেম অবস্থান নির্ধারণ, স্ক্রোল দিক নির্ধারণ | LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager |
| ItemAnimator | আইটেম যোগ, মুছে ফেলা, সরানোর জন্য অ্যানিমেশন | DefaultItemAnimator |
| ItemDecoration | আইটেমের মধ্যে বিভাজক, স্পেসিং, ব্যাকগ্রাউন্ড আঁকা | RecyclerView.ItemDecoration |
কাজের চক্র: (1) Adapter onCreateViewHolder()-এর মাধ্যমে ViewHolder তৈরি করে, (2) LayoutManager স্ক্রিনে নতুন View-এর অবস্থান নির্ধারণ করে, (3) Adapter onBindViewHolder()-এর মাধ্যমে ডেটা বাইন্ড করে, (4) স্ক্রোল করার সময়, স্ক্রিনের বাইরে চলে যাওয়া ViewHolder-গুলি পুনঃব্যবহারের জন্য পুলে (RecycledViewPool) প্রবেশ করে। নতুন View তৈরি করার পরিবর্তে, বিদ্যমানগুলি পুনঃব্যবহার করা হয় — এটি মূল কর্মক্ষমতা প্রক্রিয়া।
ViewHolder হল একটি ক্লাস যা তালিকা আইটেমের ভিতরে View (TextView, ImageView, ইত্যাদি)-এর রেফারেন্স সংরক্ষণ করে। ViewHolder ছাড়া, প্রতিটি স্ক্রোল findViewById() ট্রিগার করবে — যা Android UI-এর সবচেয়ে ব্যয়বহুল অপারেশনগুলির মধ্যে একটি। ViewHolder প্রাথমিক বাইন্ডিংয়ের পরে রেফারেন্স ক্যাশ করে এই কলটি দূর করে।
// ডেটা মডেল
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 সংজ্ঞায়িত করে যে কীভাবে আইটেমগুলি RecyclerView-এর ভিতরে অবস্থান করে। Android তিনটি ডিফল্ট বাস্তবায়ন প্রদান করে: LinearLayoutManager, GridLayoutManager এবং StaggeredGridLayoutManager। LayoutManager-এর পছন্দ ডেটা উপলব্ধি এবং স্ক্রোলিং কর্মক্ষমতা প্রভাবিত করে।
| LayoutManager | বিন্যাস | কখন ব্যবহার করবেন | সেটআপ পদ্ধতি |
|---|---|---|---|
| LinearLayoutManager | তালিকা (উল্লম্ব বা অনুভূমিক) | ফিড, চ্যাট, বিজ্ঞপ্তি, পণ্য তালিকা | LinearLayoutManager(context) |
| GridLayoutManager | N কলামের গ্রিড | গ্যালারি, ক্যাটালগ, আইকন, ছবির গ্রিড | GridLayoutManager(context, spanCount) |
| StaggeredGridLayoutManager | স্ট্যাগার্ড গ্রিড (ভিন্ন আইটেম উচ্চতা) | Pinterest বোর্ড, নোট, মেসনরি গ্যালারি | StaggeredGridLayoutManager(spanCount, orientation) |
// Fragment-এ LinearLayoutManager সেটআপ করা
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 RecyclerView-এ GoF Adapter প্যাটার্ন বাস্তবায়ন করে: এটি ডেটা (List<T>) কে স্ক্রিনে প্রদর্শিত ViewHolder-এ রূপান্তর করে। যখন ডেটা পরিবর্তিত হয়, Adapter notifyDataSetChanged(), notifyItemInserted() এবং অনুরূপ পদ্ধতির মাধ্যমে RecyclerView-কে জানাতে পারে। সমস্যা হল notifyDataSetChanged() সমস্ত দৃশ্যমান আইটেম পুনরায় আঁকে, যা জ্যাঙ্ক (jank) সৃষ্টি করে।
// কার্যকরী আপডেটের জন্য DiffUtil সহ 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-এর মাধ্যমে তালিকা আপডেট করা
fun updateArticles(newArticles: List<Article>) {
val diffCallback = ArticleDiffCallback(articles, newArticles)
val diffResult = DiffUtil.calculateDiff(diffCallback)
articles = newArticles
diffResult.dispatchUpdatesTo(this)
}
}
// DiffUtil-এর জন্য 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 Eugene W. Myers-এর পার্থক্য অ্যালগরিদম ব্যবহার করে, যা পুরানো তালিকাকে নতুনতে রূপান্তর করতে ন্যূনতম অপারেশন (সন্নিবেশ, মুছে ফেলা, সরানো, পরিবর্তন) গণনা করে। 100 আইটেমের তালিকার জন্য, DiffUtil 1–5 ms-এ কাজ করে (Google, 2025)। বড় তালিকার (10000+) জন্য, Paging লাইব্রেরি থেকে AsyncListDiffer বা PagingDataAdapter ব্যবহার করুন — তারা ব্যাকগ্রাউন্ড থ্রেডে গণনা করে।
ListView হল RecyclerView-এর পূর্বসূরী, যা Android 1.0 (API 1)-এ প্রবর্তিত হয়েছিল। এটি তালিকা প্রদর্শন করে কিন্তু ViewHolder বাধ্যতামূলক করে না, LayoutManager সমর্থন করে না এবং পরিবর্তন অ্যানিমেট করতে পারে না। RecyclerView কঠোর আর্কিটেকচার এবং ভাল কর্মক্ষমতা সহ ListView-এর প্রতিস্থাপন হিসেবে ডিজাইন করা হয়েছিল।
| মানদণ্ড | RecyclerView | ListView |
|---|---|---|
| ViewHolder | বাধ্যতামূলক (আর্কিটেকচার) | সুপারিশকৃত কিন্তু প্রয়োজনীয় নয় |
| LayoutManager | পৃথকীকরণ: তালিকা, গ্রিড, স্ট্যাগার্ড | শুধুমাত্র উল্লম্ব তালিকা |
| পরিবর্তন অ্যানিমেশন | DefaultItemAnimator বিল্ট-ইন | কোনো বিল্ট-ইন সমর্থন নেই |
| পরিবর্তন বিজ্ঞপ্তি | দানাদার: notifyItemInserted/Removed | শুধুমাত্র সম্পূর্ণ তালিকার জন্য notifyDataSetChanged() |
| DiffUtil | DiffUtil.Callback-এর মাধ্যমে সমর্থন | কোনো সমতুল্য নেই |
| বিভাজক | ItemDecoration (কাস্টম) | android:divider (বিল্ট-ইন) |
| ন্যূনতম সংস্করণ | AndroidX-এর মাধ্যমে API 14 (Android 4.0) | API 1 (সব সংস্করণ) |
Google সুপারিশ (Android Developers, 2026): সব নতুন প্রজেক্টের জন্য RecyclerView ব্যবহার করুন। ListWiki লিগেসি কোডবেসে রেখে দেওয়া যেতে পারে যেখানে মাইগ্রেশন খরচ ন্যায্য নয়। RecyclerView 100+ আইটেমে ভাল কর্মক্ষমতা প্রদান করে, অতিরিক্ত সমাধান ছাড়াই অনুভূমিক স্ক্রোলিং এবং গ্রিড সমর্থন করে। Android 15-এ, ListView আনুষ্ঠানিকভাবে আংশিকভাবে অবচিত হিসাবে চিহ্নিত।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
তিনটি শর্ত পরীক্ষা করুন: (1) Adapter recyclerView.adapter = adapter-এর মাধ্যমে সেট করা আছে, (2) LayoutManager recyclerView.layoutManager = LinearLayoutManager(context)-এর মাধ্যমে সেট করা আছে, (3) ডেটা তালিকা খালি নয় এবং adapter-কে জানানো হয়েছে (notifyDataSetChanged())। একটি সাধারণ ভুল হল notifyDataSetChanged() কল করার পরে ডেটা সেট করা। ডেটা বিজ্ঞপ্তির আগে বরাদ্দ করা উচিত। তালিকার আকার পরীক্ষা করুন: adapter.itemCount 0-এর বেশি হতে হবে।
স্ক্রোল করার সময় ধীরগতি (jank) ঘটে যখন onBindViewHolder() ভারী অপারেশন করে: ক্যাশ ছাড়া ছবি লোড করা, bind-এর ভিতরে findViewById(), জটিল গণনা। সমাধান: (1) অ্যাসিঙ্ক্রোনাস ছবি লোডিংয়ের জন্য Glide বা Coil ব্যবহার করুন, (2) সমস্ত findViewById() কল ViewHolder কনস্ট্রাক্টরে সরান, (3) ডিফ গণনার জন্য AsyncListDiffer ব্যবহার করুন। ধীর ফ্রেম খুঁজতে Android Studio-তে GPU প্রোফাইলিং (Profile GPU Rendering) সক্ষম করুন।
LayoutManager-কে ওরিয়েন্টেশন পাস করুন: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)। দ্বিতীয় প্যারামিটার হল reverseLayout (false = বাম থেকে ডানে)। অনুভূমিক গ্রিডের জন্য, অনুভূমিক ওরিয়েন্টেশন সহ GridLayoutManager বা পেজড স্ক্রোলিংয়ের জন্য কাস্টম LinearSnapHelper ব্যবহার করুন। অনুভূমিক তালিকা পণ্য, ছবি, বিভাগের ক্যারোসেলের জন্য ভাল কাজ করে।
RecyclerView-এ বিল্ট-ইন onClickClickListener নেই (ListView-এর onItemClickListener-এর বিপরীতে)। এটি ViewHolder-এ বাস্তবায়ন করুন: কনস্ট্রাক্টরে ল্যাম্বডা পাস করুন এবং itemView.setOnClickListener সেট করুন। উদাহরণ: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView)। bind()-এর ভিতরে onItemClick(article) কল করুন। বিকল্প হল অঙ্গভঙ্গি পরিচালনার জন্য RecyclerView.addOnItemTouchListener() ব্যবহার করা।
RecycledViewPool হল ViewHolder-গুলির একটি অভ্যন্তরীণ পুল যা স্ক্রোল করার সময় অদৃশ্য হয়ে গেছে। ধ্বংস হওয়ার পরিবর্তে, সেগুলি পুলে রাখা হয় এবং পুনঃব্যবহার করা হয়। ডিফল্টভাবে, পুল প্রতিটি প্রকারের 5টি ViewHolder সংরক্ষণ করে। জটিল লেআউটের জন্য আকার বাড়ান: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount)। যদি RecyclerView-এ একাধিক View প্রকার (viewType) থাকে, পুল প্রতিটির জন্য আলাদা স্ট্যাক রাখে। বিভিন্ন RecyclerViews-এর মধ্যে RecycledViewPool শেয়ার করা নেস্টেড তালিকা সহ স্ক্রিনে মেমরি বাঁচায়।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।