Android Academy · पाठ

अडैप्टर और DiffUtil

ListAdapter और DiffUtil.ItemCallback की सहायता से कुशल, एनिमेटेड सूची अडैप्टर बनाएँ। सुचारु, आंशिक अपडेट के लिए submitList() का उपयोग करें।

पाठ 6, कुल 6 में से13 चरण

अडैप्टर और DiffUtil, CoddyKit पर Android Academy का एक निःशुल्क पाठ है। यह 6 में से 6वाँ पाठ है। इस अध्ययन पथ के 3 तक कोई भी पाठ पूरा पढ़ना निःशुल्क है — इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ व्यावहारिक अभ्यास भी उपलब्ध कराता है। यह Android Academy सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Android Academy पाठ्यक्रम में कुल 6 पाठ शामिल हैं।

notifyDataSetChanged() की समस्या

जब आपके RecyclerView का डेटा बदलता है, तो notifyDataSetChanged() को कॉल करने पर हर आइटम फिर से बनाया जाता है — बदले न गए आइटम भी। इससे ये समस्याएँ होती हैं:

  • आइटम ऐनिमेशन नहीं होते
  • बड़ी सूचियों पर खराब प्रदर्शन
  • UI में झिलमिलाहट

DiffUtil बदलावों का न्यूनतम सेट निर्धारित करता है और उन्हें सहज ऐनिमेशन के साथ लागू करता है।

DiffUtil.ItemCallback

परिभाषित करें कि दो आइटम की तुलना कैसे की जाए। दो प्रश्नों के उत्तर दें:

  • areItemsTheSame — क्या वे एक ही तार्किक आइटम को दर्शाते हैं? (आमतौर पर ID की तुलना करें)
  • areContentsTheSame — क्या सभी दिखाई देने वाले फ़ील्ड समान हैं?
data class Post(val id: Int, val title: String, val likes: Int)

class PostDiffCallback : DiffUtil.ItemCallback<Post>() {

    override fun areItemsTheSame(oldItem: Post, newItem: Post): Boolean {
        return oldItem.id == newItem.id   // same post?
    }

    override fun areContentsTheSame(oldItem: Post, newItem: Post): Boolean {
        return oldItem == newItem         // data class equality (all fields)
    }
}

ListAdapter

ListAdapter एक RecyclerView.Adapter है जिसमें DiffUtil पहले से शामिल होता है। इसके कन्स्ट्रक्टर में अपना ItemCallback दें और डेटा अपडेट करने के लिए submitList() कॉल करें:

class PostAdapter : ListAdapter<Post, PostAdapter.ViewHolder>(PostDiffCallback()) {

    inner class ViewHolder(val binding: ItemPostBinding) : RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemPostBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val post = getItem(position)   // use getItem(), not a manual list
        holder.binding.tvTitle.text = post.title
        holder.binding.tvLikes.text = "${post.likes} likes"
    }
}

नई सूचियाँ सबमिट करना

जब भी आपका डेटा बदले, submitList() कॉल करें। ListAdapter पुराने और नए डेटा की तुलना बैकग्राउंड थ्रेड पर करता है और केवल आवश्यक बदलाव लागू करता है:

// In Activity or Fragment:
val adapter = PostAdapter()
binding.recyclerView.adapter = adapter

// Observe ViewModel LiveData:
viewModel.posts.observe(viewLifecycleOwner) { posts ->
    adapter.submitList(posts)   // diff calculated off main thread
}

// Important: always submit a NEW list, not a mutated old one
// WRONG:  currentList.add(newPost); adapter.submitList(currentList)
// RIGHT:  adapter.submitList(currentList + newPost)

ListAdapter में क्लिक श्रोता

क्लिक हैंडलर कन्स्ट्रक्टर के माध्यम से दें — यह एक सामान्य और साफ़ तरीका है:

class PostAdapter(
    private val onLike: (Post) -> Unit,
    private val onOpen: (Post) -> Unit
) : ListAdapter<Post, PostAdapter.ViewHolder>(PostDiffCallback()) {

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val post = getItem(position)
        holder.binding.tvTitle.text = post.title
        holder.binding.btnLike.setOnClickListener { onLike(post) }
        holder.itemView.setOnClickListener { onOpen(post) }
    }
}

// Usage:
val adapter = PostAdapter(
    onLike = { viewModel.likePost(it) },
    onOpen = { navigateToDetail(it.id) }
)

getChangePayload() — आंशिक अपडेट

जब केवल एक फ़ील्ड बदलता है (जैसे, लाइक की संख्या), तो getChangePayload() के साथ पूरे आइटम को फिर से बाँधने से बचें:

class PostDiffCallback : DiffUtil.ItemCallback<Post>() {
    override fun areItemsTheSame(oldItem: Post, newItem: Post) = oldItem.id == newItem.id
    override fun areContentsTheSame(oldItem: Post, newItem: Post) = oldItem == newItem

    override fun getChangePayload(oldItem: Post, newItem: Post): Any? {
        // Return non-null payload to trigger partial bind
        return if (oldItem.likes != newItem.likes) "likes_changed" else null
    }
}

// In Adapter.onBindViewHolder with payloads:
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: List<Any>) {
    if (payloads.contains("likes_changed")) {
        holder.binding.tvLikes.text = "${getItem(position).likes} likes"
    } else {
        super.onBindViewHolder(holder, position, payloads)
    }
}

कई View प्रकार

एक ही सूची में अलग-अलग आइटम लेआउट दिखाने के लिए getItemViewType() का उपयोग करें:

class FeedAdapter : ListAdapter<FeedItem, RecyclerView.ViewHolder>(FeedDiffCallback()) {

    companion object {
        const val TYPE_POST = 0
        const val TYPE_AD   = 1
    }

    override fun getItemViewType(position: Int): Int {
        return when (getItem(position)) {
            is FeedItem.Post -> TYPE_POST
            is FeedItem.Ad   -> TYPE_AD
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
        TYPE_POST -> PostViewHolder(ItemPostBinding.inflate(LayoutInflater.from(parent.context), parent, false))
        else      -> AdViewHolder(ItemAdBinding.inflate(LayoutInflater.from(parent.context), parent, false))
    }
}

ConcatAdapter — सूचियों का संयोजन

ConcatAdapter कई अडैप्टर को एक RecyclerView में जोड़ता है — हेडर, फ़ुटर और लोडिंग स्थितियों के लिए उपयोगी:

// Separate adapters for different sections
val headerAdapter = HeaderAdapter()
val postAdapter   = PostAdapter()
val loaderAdapter = LoadingAdapter()

// Combine them in order
binding.recyclerView.adapter = ConcatAdapter(headerAdapter, postAdapter, loaderAdapter)

// Update each independently
postAdapter.submitList(posts)
loaderAdapter.showLoading(true)

AsyncListDiffer — मैन्युअल नियंत्रण

यदि आप ListAdapter का विस्तार नहीं कर सकते, तो सीधे AsyncListDiffer का उपयोग करें:

class CustomAdapter : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

    private val differ = AsyncListDiffer(this, PostDiffCallback())

    fun submitList(list: List<Post>) = differ.submitList(list)
    fun getItem(position: Int): Post = differ.currentList[position]

    override fun getItemCount() = differ.currentList.size
}

प्रदर्शन संबंधी सुझाव

अपने RecyclerView को तेज़ बनाए रखें:

  • यदि आपके आइटम में अद्वितीय और स्थिर ID हैं, तो setHasStableIds(true) का उपयोग करें
  • onBindViewHolder के अंदर ऑब्जेक्ट बनाने से बचें
  • कई RecyclerView के बीच पुनर्चक्रित दृश्यों को साझा करने के लिए RecycledViewPool का उपयोग करें
  • ऑफ़-स्क्रीन कैश बढ़ाने के लिए setItemViewCacheSize() का उपयोग करें

ऐनिमेशन अपने-आप मिलते हैं

ListAdapter का DiffUtil एकीकरण इन स्थितियों के लिए अपने-आप DefaultItemAnimator सक्रिय करता है:

  • नए आइटम के लिए धीरे-धीरे दिखाई देना
  • हटाए गए आइटम के लिए धीरे-धीरे गायब होना
  • आइटम का स्थान बदलने पर स्थान-परिवर्तन ऐनिमेशन

कस्टम ऐनिमेटर सेट करें: recyclerView.itemAnimator = MyAnimator()। सभी ऐनिमेशन बंद करने के लिए इसे null पर सेट करें।

त्वरित जाँच

DiffUtil.ItemCallback में आपको किन दो विधियों को लागू करना आवश्यक है?

पुनरावलोकन: अडैप्टर और DiffUtil

कम से कम कोड में कुशल और ऐनिमेशन वाली सूचियाँ:

  • DiffUtil.ItemCallback — पहचान (areItemsTheSame) और समानता (areContentsTheSame) परिभाषित करें
  • ListAdapter — अंतर्निहित एसिंक्रोनस तुलना; submitList() कॉल करें
  • हमेशा नई सूची का संदर्भ सबमिट करें, वर्तमान सूची को कभी न बदलें
  • आंशिक पुनः-बाइंडिंग के लिए getChangePayload()
  • कई अडैप्टर को संयोजित करने के लिए ConcatAdapter

अगला विषय: Navigation Component के साथ कई स्क्रीन के बीच नेविगेशन।

शुरुआत निःशुल्क

एआई शिक्षक के साथ Kotlin सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
36
पाठ
152

अक्सर पूछे जाने वाले प्रश्न

क्या “अडैप्टर और DiffUtil” पाठ निःशुल्क है?

हाँ — Android Academy अध्ययन पथ के 3 तक कोई भी पाठ, जिसमें “अडैप्टर और DiffUtil” भी शामिल है, यहाँ वेब पर पूरा पढ़ना निःशुल्क है। इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ इंटरैक्टिव अभ्यास भी उपलब्ध कराता है। Android Academy पाठ्यक्रम में कुल 6 पाठ शामिल हैं।

“अडैप्टर और DiffUtil” में मैं क्या सीखूँगा?

ListAdapter और DiffUtil.ItemCallback की सहायता से कुशल, एनिमेटेड सूची अडैप्टर बनाएँ। सुचारु, आंशिक अपडेट के लिए submitList() का उपयोग करें। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Android Academy का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या Android Academy शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Android Academy शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 6 में से 6वाँ पाठ है।

“अडैप्टर और DiffUtil” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस Android Academy पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर Android Academy पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. Kotlin कलेक्शन
  2. RecyclerView की मूल बातें
  3. RecyclerView क्लिक इवेंट
  4. SharedPreferences
  5. DataStore प्राथमिकताएँ
  6. अडैप्टर और DiffUtil
← Android Academy पर वापस जाएँ