हेलो सब लोग!
इस लेख में, मैं RecyclerView का उपयोग करते समय अनुकूलन के त्वरित तरीकों पर नज़र डालना चाहूंगा।
रीसाइक्लर व्यू एक यूजर इंटरफ़ेस घटक है, यानी एक ऐसा तत्व जिसे इंटरफ़ेस में जोड़कर आसानी से सूची प्रदर्शित की जा सकती है। यह कोड में बनाया गया है और इसमें सूची को प्रदर्शित करने, एनिमेट करने और ऑप्टिमाइज़ करने के लिए पहले से ही उपकरण मौजूद हैं, और यह कस्टमाइज़ेशन सेटिंग्स का भी समर्थन करता है।
RecyclerView को सही ढंग से काम करने के लिए, आपको निम्नलिखित घटकों को लागू करना होगा:
RecyclerView
, जिसे हमारी गतिविधि के लेआउट में जोड़ा जाना चाहिए;Adapter
, जो सूची के साथ डेटा को सम्मिलित करता है, संसाधित करता है और संबद्ध करता है;ListAdapter
, Adapter को अद्यतन करता है और कन्स्ट्रक्टर में DiffUtil को स्वीकार करता है;ViewHolder
, जो संसाधनों को अनुकूलित करने के लिए कार्य करता है और सूची में शामिल सभी तत्वों के लिए एक प्रकार का कंटेनर है;DiffUtil
, जिसका उपयोग सूची को अनुकूलित करने के लिए किया जाता है।
मैं यह नहीं बताऊंगा कि इसे शुरू से कैसे लागू किया जाए, आप इसे लिंक पर पा सकते हैं।
बाइंडिंग करते समय ViewHolder में संसाधनों और कास्टिंग तक पहुंच हटाएँ।
उदाहरण के लिए, नीचे दिया गया कोड लें:
data class TrackingUiModel( val id: Long, val title: String, @ColorRes val color: Int, val eventId: Long, val state: TrackingState, val startTime: Long, val endTime: Long, val countTime: Long, val formattedTime: String, ) class TrackingViewHolder(itemView: View): ViewHolder(itemView) { private val binding : TrackingItemBinding by viewBinding() @SuppressLint("SetTextI18n") fun bind(data: TrackingUiModel) { val stateText = when (data.state) { TrackingState.START -> itemView.context.getString(R.string.in_progress) TrackingState.PAUSE -> itemView.context.getString(R.string.pause) else -> { "" } } binding.eventId.text = data.eventId.toString() binding.eventTitle.text = "${data.title} $stateText" binding.eventColor.setBackgroundColor(ContextCompat.getColor(itemView.context, data.color)) binding.countTextView.text = data.formattedTime } }
हर बार जब bind
विधि को कॉल किया जाता है, तो getString
और getColor
कॉल को कॉल किया जाएगा, और स्ट्रिंग कास्टिंग के लिए toString
भी कॉल किया जाएगा। इस तरह हम अधिक मेमोरी का उपभोग करते हैं। और आपको यह सुनिश्चित करने की आवश्यकता है कि bind
विधि जल्दी से निष्पादित हो, और आपको यह सुनिश्चित करने का प्रयास करना चाहिए कि ViewHolder
कार्य केवल सूची आइटम प्रदर्शित कर रहा है। अनुकूलन के लिए, TrackingUiModel
ऑब्जेक्ट में स्ट्रिंग eventId
, stateText
और color प्राप्त करना बेहतर है।
अनुकूलित कोड अब इस तरह दिखता है:
data class TrackingUiModel( val id: Long, val title: String, val color: Int, val eventId: String, val state: TrackingState, val stateText: String, val startTime: Long, val endTime: Long, val countTime: Long, val formattedTime: String, ) class TrackingViewHolder(itemView: View): ViewHolder(itemView) { private val binding : TrackingItemBinding by viewBinding() fun bind(data: TrackingUiModel) { binding.eventId.text = data.eventId binding.eventTitle.text = "${data.title} ${data.stateText}" binding.eventColor.setBackgroundColor(data.color) binding.countTextView.text = data.formattedTime } }
हमने ViewHolder
से आगे सब कुछ ले लिया है, हमें जो कुछ भी चाहिए और तैयार है वह TrackingUiModel
में प्राप्त होगा।
यदि आप RecyclerView.Adapter
उपयोग कर रहे हैं तो आपको ListAdapter
पर स्विच करना चाहिए, और इसके साथ DiffUtil
उपयोग करना चाहिए।
उदाहरण के लिए, नीचे दिया गया कोड लें:
class TrackingAdapter: RecyclerView.Adapter<TrackingViewHolder>(){ private val mItems = mutableListOf<TrackingUiModel>() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrackingViewHolder { return TrackingViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.tracking_item, parent, false)) } override fun getItemCount(): Int = mItems.size override fun onBindViewHolder(holder: TrackingViewHolder, position: Int) { holder.bind(mItems[position]) } fun setItems(items: List<TrackingUiModel>){ mItems.clear() mItems.addAll(items) notifyDataSetChanged() } }
सूची तत्वों को जोड़ते समय, setItems
विधि को कॉल करने से सूची साफ़ हो जाती है, सूची तत्व जुड़ जाते हैं, और अंत में notifyDataSetChanged
कॉल किया जाता है।
आइए कल्पना करें कि हम सूची को बदलते या अपडेट करते हैं, और हर बार setItems
विधि को कॉल किया जाएगा; यह काफी संसाधन-खपत होगा। इस कारण से, ListAdapter
और DiffUtil
उपयोग करना बेहतर है।
नीचे एक संशोधित TrackingAdapter
है जो ListAdapter
क्रियान्वित करता है और DiffUtil
उपयोग करता है; मेरे उदाहरण में, यह TrackingDiffCallback
वर्ग है।
सूची जोड़ने के लिए, हम trackingAdapter.submitList
विधि का उपयोग करते हैं, और अंत में, एडाप्टर हमारे लिए सूची को अद्यतन करने का सारा काम कर देगा।
class TrackingAdapter: ListAdapter<TrackingUiModel, TrackingViewHolder>(TrackingDiffCallback()){ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrackingViewHolder { return TrackingViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.tracking_item, parent, false)) } override fun onBindViewHolder(holder: TrackingViewHolder, position: Int) { holder.bind(getItem(position)) } }
class TrackingDiffCallback: DiffUtil.ItemCallback<TrackingUiModel>() { override fun areItemsTheSame(oldItem: TrackingUiModel, newItem: TrackingUiModel): Boolean { return oldItem.id == newItem.id } override fun areContentsTheSame(oldItem: TrackingUiModel, newItem: TrackingUiModel): Boolean { return oldItem == newItem } }
ऐसे मामले हैं जैसे सूची आइटम को पसंदीदा में जोड़ना, छवि बदलना, या सूची आइटम के किसी अन्य दृश्य को बदलना। जब इन सभी मामलों में परिवर्तन होते हैं, तो ViewHolder
में बाइंड विधि को फिर से बुलाया जाता है, और हम तत्व के हाइलाइट को दृष्टिगत रूप से देखते हैं। ऐसा होने से रोकने के लिए, पेलोड मदद के लिए हमारे पास आता है।
पेलोड का उपयोग करने के लिए, आइए ViewHolder
, DiffUtil
, और Adapter
में परिवर्तन करें।
मेरे मामले में, मैं निम्नलिखित परिवर्तन करूंगा।
TrackingViewHolder में, हम उस डेटा के साथ एक बाइंड विधि जोड़ते हैं जिसे बदलने की आवश्यकता होती है।
fun bind(data: TrackingUiModel, newTime: String) { binding.eventId.text = data.eventId binding.eventTitle.text = "${data.title} ${data.stateText}" binding.eventColor.setBackgroundColor(data.color) binding.countTextView.text = newTime }
TrackingDiffCallback
में, हम getChangePayload
विधि को ओवरराइड करते हैं और बदले जा रहे फ़ील्ड की तुलना करते हैं। मेरे मामले में, यह formattedTime
है।
override fun getChangePayload(oldItem: TrackingUiModel, newItem: TrackingUiModel): Any? { if (oldItem.formattedTime != newItem.formattedTime) return newItem.formattedTime return super.getChangePayload(oldItem, newItem) }
TrackingListAdapter,
हम onBindViewHolder
विधि को पेलोड के साथ ओवरराइड करते हैं। हम जाँचते हैं कि पेलोड खाली है या नहीं, अगर यह खाली नहीं है, तो हम पहला तत्व प्राप्त करते हैं और पेलोड के लिए बाइंड विधि को कॉल करते हैं।
override fun onBindViewHolder(holder: TrackingViewHolder, position: Int, payloads: MutableList<Any>) { if (payloads.isEmpty()) { super.onBindViewHolder(holder, position, payloads) } else { val newTime = payloads.firstOrNull() as? String ?: "" holder.bind(getItem(position), newTime) } }
संदर्भ लिंक: