Android Kotlin की बुनियादी जानकारी 07.2: DiffUtil और RecyclerView के साथ डेटा बाइंडिंग

यह कोडलैब Android Kotlin के बुनियादी कोर्स में शामिल है. अगर आप कोडलैब के क्रम में काम करते हैं, तो आपको इस कोर्स का ज़्यादा से ज़्यादा फ़ायदा मिलेगा. सभी कोर्स कोडलैब Android Kotlin से जुड़े बेसिक कोडलैब के लैंडिंग पेज पर दिए गए हैं.

परिचय

पिछले कोडलैब में आपने RecyclerView में नींद की क्वालिटी के बारे में डेटा दिखाने के लिए, ट्रैकरMySleepquality ऐप्लिकेशन को अपडेट किया था. पहली बार RecyclerView बनाते समय आपने जो तकनीक सीखीं, वह ज़्यादातर RecyclerViews के लिए काफ़ी हैं. इनमें ऐसी आसान सूचियां दिखाई जाती हैं जो बहुत बड़ी न हों. हालांकि, ऐसी कई तकनीकें हैं जो RecyclerView को बड़ी सूचियों के लिए ज़्यादा असरदार बनाती हैं. साथ ही, आपके कोड को बनाए रखना और जटिल सूचियों और ग्रिड के लिए इसे बढ़ाना आसान बनाती हैं.

इस कोडलैब में, आप पिछले कोडलैब के आधार पर, स्लीप-ट्रैकर ऐप्लिकेशन पर बनाते हैं. आप नींद के डेटा की सूची को अपडेट करने का ज़्यादा असरदार तरीका जानते हैं. साथ ही, आप RecyclerView के साथ डेटा बाइंडिंग का इस्तेमाल करने का तरीका जानते हैं. (अगर आपके पास पिछले कोडलैब से ऐप्लिकेशन नहीं है, तो आप इस कोडलैब के लिए स्टार्टर कोड डाउनलोड कर सकते हैं.)

आपको क्या पता होना चाहिए

  • किसी ऐक्टिविटी, फ़्रैगमेंट, और व्यू का इस्तेमाल करके बेसिक यूज़र इंटरफ़ेस बनाना.
  • फ़्रैगमेंट के बीच नेविगेट करना और फ़्रैगमेंट के बीच डेटा पास करने के लिए, safeArgs का इस्तेमाल करना.
  • मॉडल, मॉडल फ़ैक्ट्री, बदलाव, और उनके LiveData की निगरानी करें.
  • Room डेटाबेस बनाने, डीएओ बनाने, और इकाइयों की जानकारी देने का तरीका.
  • डेटाबेस और लंबे समय तक चलने वाले अन्य कामों के लिए कोरूटीन इस्तेमाल करने का तरीका.
  • Adapter, ViewHolder, और आइटम लेआउट के साथ बेसिक RecyclerView को लागू करने का तरीका.

आप इन चीज़ों के बारे में जानेंगे

  • RecyclerView की ओर से दिखाई गई सूची को बेहतर तरीके से अपडेट करने के लिए, DiffUtil का इस्तेमाल कैसे करें.
  • RecyclerView के साथ डेटा बाइंडिंग का इस्तेमाल करने का तरीका.
  • डेटा में बदलाव करने के लिए बाइंडिंग अडैप्टर का इस्तेमाल कैसे करें.

आप क्या कर पाएंगे!

  • इस सीरीज़ के पिछले कोडलैब से, ShowMySleepquality ऐप्लिकेशन पर बनाएं.
  • DiffUtil का इस्तेमाल करके, सूची को बेहतर तरीके से अपडेट करने के लिए, SleepNightAdapter को अपडेट करें.
  • डेटा बदलने के लिए बाइंडिंग अडैप्टर का इस्तेमाल करके, RecyclerView के लिए डेटा बाइंडिंग लागू करें.

स्लीप-ट्रैकर ऐप्लिकेशन में, फ़्रैगमेंट से दिखने वाली दो स्क्रीन होती हैं. जैसा कि नीचे दी गई इमेज में दिखाया गया है.

बाईं ओर दिखाई गई पहली स्क्रीन पर, ट्रैकिंग शुरू और बंद करने के लिए बटन दिए गए हैं. स्क्रीन पर उपयोगकर्ता के सोने के कुछ डेटा की जानकारी दिखती है. हटाएं बटन, उपयोगकर्ता के लिए ऐप्लिकेशन के ज़रिए इकट्ठा किया गया सारा डेटा हमेशा के लिए मिटा देता है. दाईं ओर दिखाई गई दूसरी स्क्रीन, अच्छी क्वालिटी वाली रेटिंग चुनने के लिए है.

इस ऐप्लिकेशन को यूज़र इंटरफ़ेस (यूआई) कंट्रोलर, ViewModel, और LiveData के साथ-साथ Room डेटाबेस का इस्तेमाल करके, नींद से जुड़े डेटा को बनाए रखने के लिए डिज़ाइन किया गया है.

नींद का डेटा RecyclerView में दिखेगा. इस कोडलैब में, आप RecyclerView के लिए DiffUtil और डेटा-बाइंडिंग वाला हिस्सा बनाते हैं. इस कोडलैब के बाद, आपका ऐप्लिकेशन काफ़ी हद तक एक जैसा दिखेगा. हालांकि, यह काफ़ी आसान और मापने में आसान होगा.

आप पिछले कोडलैब से SleepTracker ऐप्लिकेशन का इस्तेमाल जारी रख सकते हैं या GitHub से RecyclerViewDiffUtilDataBinding-Starter ऐप्लिकेशन डाउनलोड कर सकते हैं.

  1. अगर ज़रूरत हो, तो GitHub से RecyclerViewDiffUtilDataBinding-Starter ऐप्लिकेशन डाउनलोड करें और प्रोजेक्ट को Android Studio में खोलें.
  2. ऐप्लिकेशन चलाएं.
  3. SleepNightAdapter.kt फ़ाइल खोलें.
  4. ऐप्लिकेशन के स्ट्रक्चर से जुड़ी जानकारी पाने के लिए, कोड की जांच करें. उपयोगकर्ता को नींद से जुड़ा डेटा दिखाने के लिए, अडैप्टर पैटर्न के साथ RecyclerView का इस्तेमाल करने के रीकैप के लिए नीचे दिया गया डायग्राम देखें.

  • उपयोगकर्ता के इनपुट से, ऐप्लिकेशन SleepNight ऑब्जेक्ट की सूची बनाता है. हर SleepNight ऑब्जेक्ट, एक रात की नींद, उसके कुल समय, और क्वालिटी को दिखाता है.
  • SleepNightAdapter SleepNight ऑब्जेक्ट की सूची को RecyclerView इस्तेमाल करने और दिखाने के लिए इस्तेमाल करता है.
  • SleepNightAdapter अडैप्टर ViewHolders बनाता है. इसमें रीसाइकलर व्यू के लिए डेटा, व्यू, और मेटा जानकारी होती है, ताकि डेटा दिखाया जा सके.
  • RecyclerView की मदद से, SleepNightAdapter का इस्तेमाल करके यह तय किया जा सकता है कि कितने आइटम दिखाने के लिए मौजूद हैं. getItemCount(). RecyclerView का इस्तेमाल करके, onCreateViewHolder() और onBindViewHolder() की मदद से, व्यू होल्डर दिखाए जा सकते हैं.

AndroidManifestDataSetChanged() विधि अक्षम है

RecyclerView को यह बताने के लिए कि सूची का कोई आइटम बदल गया है और उसे अपडेट करने की ज़रूरत है, मौजूदा कोड notifyDataSetChanged() को SleepNightAdapter में कॉल करता है, जैसा कि नीचे दिखाया गया है.

var data =  listOf<SleepNight>()
   set(value) {
       field = value
       notifyDataSetChanged()
   }

हालांकि, notifyDataSetChanged() से RecyclerView को यह पता चलता है कि पूरी सूची अमान्य है. ऐसा करने से, RecyclerView सूची के हर आइटम को फिर से पिन करता है और उसे फिर से दिखाता है. इनमें वे आइटम भी शामिल होते हैं जो स्क्रीन पर नहीं दिखते. यह बहुत मेहनत का काम है. बड़ी या जटिल सूचियों के लिए, इस प्रोसेस में इतना समय लग सकता है कि उपयोगकर्ता सूची को स्क्रोल करते समय डिसप्ले फ़्लिकर या स्टटर कर लेता है.

इस समस्या को ठीक करने के लिए, आप RecyclerView को सटीक तौर पर बता सकते हैं कि क्या बदलाव हुए हैं. इसके बाद, RecyclerView सिर्फ़ उन व्यू को अपडेट कर सकता है जो स्क्रीन पर बदले गए हैं.

RecyclerView में किसी एक एलिमेंट को अपडेट करने के लिए, एक रिच एपीआई है. आप RecyclerView को यह बताने के लिए notifyItemChanged() का इस्तेमाल कर सकते हैं कि किसी आइटम को बदल दिया गया है. साथ ही, आप जोड़े गए, हटाए गए या ले जाए गए आइटम के लिए, मिलते-जुलते फ़ंक्शन का इस्तेमाल कर सकते हैं. आप यह सब मैन्युअल रूप से कर सकते हैं, लेकिन यह काम सामान्य नहीं होगा. इसमें बहुत ज़्यादा कोड शामिल हो सकता है.

सबसे अच्छी बात यह है कि #39; एक बेहतर तरीका है.

DiffUtil बेहतर तरीके से काम करता है और आपके लिए कड़ी मेहनत करता है

RecyclerView के पास DiffUtil नाम की एक क्लास है, जो दो सूचियों के बीच के फ़र्क़ का हिसाब लगाती है. DiffUtil एक पुरानी सूची और एक नई सूची तैयार करती है, जिससे पता चलता है कि सभी के लिए क्या अलग है. यह ऐसे आइटम को ढूंढता है जिन्हें जोड़ा गया, हटाया गया था या जिनमें बदलाव किया गया था. इसके बाद, यह एल्गोरिदम यूजीन डब्ल्यू मायर' के बीच अंतर का एल्गोरिदम पता करता है.

DiffUtil को यह पता चलने पर कि क्या बदलाव हुए हैं, RecyclerView उस जानकारी का इस्तेमाल सिर्फ़ उन आइटम को अपडेट करने के लिए कर सकता है जिनमें बदलाव किया गया हो, उन्हें जोड़ा गया हो, हटाया गया हो या किसी दूसरी जगह ले जाया गया हो. यह पूरी सूची को फिर से तैयार करने के मुकाबले ज़्यादा असरदार होता है.

इस टास्क को RecyclerView में ऑप्टिमाइज़ करने के लिए, SleepNightAdapter को अपग्रेड करें, ताकि डेटा में होने वाले बदलावों के लिए, RecyclerView को ऑप्टिमाइज़ किया जा सके.

पहला चरण: SleepNightDiffCallback लागू करना

DiffUtil क्लास की सुविधा इस्तेमाल करने के लिए, DiffUtil.ItemCallback को बढ़ाएं.

  1. SleepNightAdapter.kt खोलें.
  2. SleepNightAdapter के लिए फ़ुल क्लास परिभाषा के नीचे, SleepNightDiffCallback नाम की एक नई टॉप-लेवल क्लास बनाएं, जो DiffUtil.ItemCallback को बढ़ाती है. SleepNight को जेनरिक पैरामीटर के तौर पर पास करें.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
  1. कर्सर को SleepNightDiffCallback क्लास के नाम में रखें.
  2. Alt+Enter(Option+EnterMac पर देखें) और सदस्य लागू करें.
  3. डायलॉग बॉक्स खुलने पर, areItemsTheSame() और areContentsTheSame() तरीके चुनने के लिए Shift पर बायां क्लिक करें. इसके बाद, ठीक है पर क्लिक करें.

    यह SleepNightDiffCallback के अंदर स्टब जनरेट करता है, जैसा कि नीचे दिखाया गया है. DiffUtil इन तरीकों का इस्तेमाल करके पता लगाता है कि सूची और आइटम कैसे बदले गए हैं.
    override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
  1. areItemsTheSame() के अंदर, TODO को ऐसे कोड से बदलें जो यह जांच करता हो कि पास किए गए दो SleepNight आइटम, oldItem और newItem एक जैसे हैं या नहीं. अगर सामान के पास एक ही nightId है, तो उनका सामान एक ही है. इसलिए, true दिखाएं. अगर ऐसा नहीं है, तो false दिखाएं. DiffUtil इस टेस्ट का इस्तेमाल करके, यह पता लगाता है कि कोई आइटम जोड़ा गया, हटाया गया या किसी दूसरी जगह ले जाया गया है.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
   return oldItem.nightId == newItem.nightId
}
  1. areContentsTheSame() के अंदर, यह देखें कि oldItem और newItem में एक ही डेटा है या नहीं. इसका मतलब, यह कि क्या वे बराबर हैं. यह 'बराबर है' की जांच सभी फ़ील्ड की जांच करेगी, क्योंकि SleepNight एक डेटा क्लास है. Data क्लास आपके लिए equals और कुछ दूसरे तरीके अपने-आप तय करती हैं. अगर oldItem और newItem के बीच अंतर हैं, तो यह कोड DiffUtil को बताता है कि आइटम अपडेट कर दिया गया है.
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
   return oldItem == newItem
}

बदलाव करने वाली सूची को दिखाने के लिए, RecyclerView का इस्तेमाल करना एक आम पैटर्न है. RecyclerView एक अडैप्टर क्लास, ListAdapter देता है, जो आपकी मदद के लिए एक RecyclerView अडैप्टर बनाता है. इस अडैप्टर के बाद RecyclerView होता है.

ListAdapter आपके लिए सूची पर नज़र रखता है और सूची अपडेट होने पर अडैप्टर को सूचना देता है.

पहला चरण: ListAdapter इस्तेमाल करने के लिए, अडैप्टर को बदलना

  1. ListAdapter को बढ़ाने के लिए, SleepNightAdapter.kt फ़ाइल में SleepNightAdapter का क्लास हस्ताक्षर बदलें.
  2. अगर कहा जाए, तो androidx.recyclerview.widget.ListAdapter इंपोर्ट करें.
  3. SleepNightAdapter.ViewHolder में SleepNight को ListAdapter में पहले आर्ग्युमेंट के तौर पर जोड़ें.
  4. SleepNightDiffCallback() को कंस्ट्रक्टर में पैरामीटर के रूप में जोड़ें. ListAdapter इसका इस्तेमाल यह जानने के लिए करेगा कि सूची में क्या बदलाव हुआ है. कक्षा खत्म होने के बाद, आपका SleepNightAdapter हस्ताक्षर नीचे दिखाई देना चाहिए.
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
  1. SleepNightAdapter क्लास के अंदर, सेटर के साथ-साथ data फ़ील्ड को मिटा दें. आपको अब इसकी ज़रूरत नहीं है, क्योंकि ListAdapter आपके लिए सूची का ट्रैक रखता है.
  2. getItemCount() का ओवरराइड मिटाएं, क्योंकि ListAdapter आपके लिए यह तरीका लागू करता है.
  3. onBindViewHolder() की गड़बड़ी को हटाने के लिए, item वैरिएबल बदलें. item पाने के लिए data के बजाय, ListAdapter में दिए गए getItem(position) तरीके का इस्तेमाल करें.
val item = getItem(position)

दूसरा चरण: सूची को अपडेट रखने के लिए,SubmitList() का इस्तेमाल करना

बदली गई सूची उपलब्ध होने पर, आपके कोड को ListAdapter को बताना होगा. ListAdapter, submitList() नाम का एक तरीका उपलब्ध कराता है, ताकि ListAdapter को बताया जा सके कि सूची का नया वर्शन उपलब्ध है. इस तरीके का इस्तेमाल करने पर, ListAdapter नई सूची को पुरानी सूची से हटा देता है और उन आइटम का पता लगाता है जो जोड़े गए, हटाए गए, हटाए गए या बदले गए हैं. इसके बाद, ListAdapter RecyclerView के दिखाए गए आइटम अपडेट करता है.

  1. SleepTrackerFragment.kt खोलें.
  2. onCreateView() के sleepTrackerViewModel में, ऑब्ज़र्वर में गड़बड़ी देखें. इसमें वह data वैरिएबल है जिसे आपने और #39;मिटाया है.
  3. adapter.data = it को adapter.submitList(it) पर कॉल करें. अपडेट किया गया कोड नीचे दिखाया गया है.

sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
   it?.let {
       adapter.submitList(it)
   }
})
  1. अपना ऐप्लिकेशन चलाएं. यह तेज़ी से काम करता है, अगर आपकी सूची छोटी है, तो यह बिल्कुल नहीं दिखेगा.

इस टास्क में, डेटा बाइंडिंग को सेट अप करने के लिए, पिछले कोडलैब के समान तकनीक का इस्तेमाल किया जाता है. साथ ही, findViewById() में कॉल खत्म किए जाते हैं.

पहला चरण: लेआउट फ़ाइल में डेटा बाइंडिंग जोड़ना

  1. टेक्स्ट टैब में, list_item_sleep_night.xml लेआउट फ़ाइल खोलें.
  2. कर्सर को ConstraintLayout टैग पर रखें और Alt+Enter (Mac पर Option+Enter ) दबाएं. इंटेंट मेन्यू ("क्विक फ़िक्स&कोटेशन; मेन्यू) खुलता है.
  3. डेटा बाइंडिंग लेआउट में बदलें चुनें. ऐसा करने से, लेआउट को <layout> में जोड़ दिया जाता है. साथ ही, इसमें <data> टैग जोड़ा जाता है.
  4. ज़रूरत पड़ने पर, सबसे ऊपर तक स्क्रोल करें और <data> टैग में sleep नाम वाले वैरिएबल का एलान करें.
  5. अपने type को SleepNight, com.example.android.trackmysleepquality.database.SleepNight का पूरी तरह क्वालिफ़ाइड नाम दें. आपका पूरा <data> टैग नीचे दिखाए गए तरीके से दिखना चाहिए.
   <data>
        <variable
            name="sleep"
            type="com.example.android.trackmysleepquality.database.SleepNight"/>
    </data>
  1. Binding ऑब्जेक्ट को ज़बरदस्ती बनाने के लिए, Create > Clean Project चुनें. इसके बाद, Create > प्रोजेक्ट दोबारा बनाएं चुनें. (अगर आपको अब भी समस्याएं आ रही हैं, तो फ़ाइल > कैश मेमोरी चालू करें / रीस्टार्ट करें चुनें.) ListItemSleepNightBinding बाइंडिंग ऑब्जेक्ट के साथ, प्रोजेक्ट और #39; जनरेट की गई फ़ाइलें प्रोजेक्ट में जोड़ दी जाती हैं.

दूसरा चरण: डेटा बाइंडिंग का इस्तेमाल करके आइटम के लेआउट को इनफ़्लेट करना

  1. SleepNightAdapter.kt खोलें.
  2. ViewHolder क्लास में, from() तरीका ढूंढें.
  3. view वैरिएबल का एलान मिटाएं.

मिटाने के लिए कोड:

val view = layoutInflater
       .inflate(R.layout.list_item_sleep_night, parent, false)
  1. जहां view वैरिएबल था, वहां binding नाम का एक नया वैरिएबल तय करें, जो ListItemSleepNightBinding बाइंडिंग ऑब्जेक्ट को बढ़ाता है, जैसा कि नीचे दिखाया गया है. बाइंडिंग ऑब्जेक्ट का ज़रूरी इंपोर्ट करें.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
  1. फ़ंक्शन के खत्म होने पर, view लौटाने के बजाय, binding दिखाएं.
return ViewHolder(binding)
  1. गड़बड़ी से छुटकारा पाने के लिए, अपने कर्सर को binding शब्द पर रखें. इंटेंट मेन्यू खोलने के लिए, Alt+Enter (Mac पर Option+Enter) दबाएं.
  1. पैरामीटर बदलें #39;itemView' क्लास के मुख्य कंस्ट्रक्टर का प्रकार 'ViewHolder' को 'ListItemSleepNightBinding' चुनें. इससे, ViewHolder क्लास के पैरामीटर टाइप को अपडेट किया जाता है.

  1. हस्ताक्षर में हुए बदलाव देखने के लिए, ViewHolder की क्लास डेफ़िनिशन तक स्क्रोल करें. आपको itemView के लिए गड़बड़ी दिख रही है, क्योंकि आपने from() तरीके में itemView को बदलकर binding कर दिया है.

    ViewHolder कक्षा की परिभाषा में, itemView में से किसी एक इंस्टेंस पर दायां क्लिक करें और रीफ़ैक्टर &g; नाम बदलें को चुनें. नाम को बदलकर binding करें.
  2. प्रॉपर्टी बनाने के लिए, binding पैरामीटर val का इस्तेमाल करें.
  3. पैरंट क्लास RecyclerView.ViewHolder को किए जाने वाले कॉल में, पैरामीटर को binding से बदलकर binding.root करें. आपको View पास करना होगा. binding.root आपके आइटम के लेआउट में रूट ConstraintLayout होता है.
  4. आपने कक्षा के लिए जो एलान किया था वह नीचे दिए गए कोड जैसा दिखना चाहिए.
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){

आपको findViewById() पर कॉल करने के दौरान भी गड़बड़ी दिख रही है. साथ ही, आप इसे ठीक कर रहे हैं.

तीसरा चरण: findViewById() को बदलना

अब आप sleepLength, quality, और qualityImage प्रॉपर्टी को findViewById() के बजाय, binding ऑब्जेक्ट का इस्तेमाल करने के लिए अपडेट कर सकते हैं.

  1. जैसा कि नीचे दिखाया गया है, binding ऑब्जेक्ट के व्यू का इस्तेमाल करने के लिए sleepLength, qualityString, और qualityImage के शुरू करने के तरीके को बदलें. इसके बाद, आपके कोड में और कोई गड़बड़ी नहीं दिखेगी.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage

बाइंडिंग ऑब्जेक्ट के साथ, आपको अब sleepLength, quality, और qualityImage प्रॉपर्टी को तय करने की ज़रूरत नहीं है. DataBinding, लुकअप को कैश मेमोरी में सेव करेगा, इसलिए इन प्रॉपर्टी का एलान नहीं करना होगा.

  1. sleepLength, quality, और qualityImage प्रॉपर्टी के नामों पर दायां क्लिक करें. ReACTOR > इनलाइन चुनें या Control+Command+N (Mac पर Option+Command+N) दबाएं.
  2. अपना ऐप्लिकेशन चलाएं. अगर आपके प्रोजेक्ट में कोई गड़बड़ी है, तो आपको अपने-आप और बिल्डिंग करना होगा.)

इस टास्क में, आप अपने ऐप्लिकेशन को अपग्रेड करते हैं, ताकि आपके व्यू में डेटा सेट करने के लिए बाइंडिंग अडैप्टर का इस्तेमाल कर सकें.

पिछले कोडलैब में, LiveData लेने और टेक्स्ट व्यू में दिखाने के लिए, फ़ॉर्मैट की गई स्ट्रिंग जनरेट करने के लिए Transformations क्लास का इस्तेमाल किया जाता था. हालांकि, अगर आपको अलग-अलग तरह के टाइप या कॉम्प्लेक्स टाइप को बाइंड करना है, तो बाइंडिंग बाइंडिंग का इस्तेमाल करके डेटा बाइंडिंग में उन टाइप का इस्तेमाल किया जा सकता है. बाइंडिंग अडैप्टर ऐसे अडैप्टर होते हैं जो आपका डेटा लेते हैं और उसे किसी ऐसी चीज़ में बदल देते हैं जिसका इस्तेमाल डेटा बाइंडिंग से कोई व्यू, जैसे कि टेक्स्ट या इमेज को बाइंड करने के लिए किया जा सके.

आप तीन बाइंडिंग अडैप्टर लागू करने जा रहे हैं, एक क्वालिटी इमेज के लिए और एक हर टेक्स्ट फ़ील्ड के लिए. खास जानकारी में, बाइंडिंग अडैप्टर का एलान करने के लिए एक तरीका बताया गया है, जिसमें एक आइटम और एक व्यू होता है. साथ ही, @BindingAdapter के साथ एनोटेट करता है. तरीके के मुख्य हिस्से में आप ट्रांसफ़ॉर्मेशन लागू करते हैं. Kotlin में, डेटा पाने वाले व्यू क्लास पर एक्सटेंशन फ़ंक्शन के तौर पर बाइंडिंग अडैप्टर लिखा जा सकता है.

पहला चरण: बाइंडिंग अडैप्टर बनाना

ध्यान दें कि आपको चरण में कई कक्षाओं को इंपोर्ट करना होगा. इसके लिए, इसे अलग-अलग कॉल नहीं किया जाएगा.

  1. SleepNightAdapater.kt खोलें.
  2. ViewHolder क्लास में, bind() तरीका ढूंढें और खुद को याद दिलाएं कि यह तरीका क्या करता है. आपको binding.sleepLength, binding.quality, और binding.qualityImage के लिए वैल्यू का हिसाब लगाने वाला कोड लेना होगा. इसके बजाय, अडैप्टर में इसका इस्तेमाल करना होगा. (अभी के लिए, कोड को ऐसे ही छोड़ दें; उसे बाद के चरण में ले जाएं.)
  3. sleeptracker पैकेज में, BindingUtils.kt नाम की फ़ाइल बनाएं और खोलें.
  4. TextView पर एक्सटेंशन फ़ंक्शन का एलान करें, जिसे setSleepDurationFormatted कहते हैं और SleepNight में पास करें. यह फ़ंक्शन आपकी नींद के कुल समय का हिसाब लगाने और उसे फ़ॉर्मैट करने के लिए इस्तेमाल होगा.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
  1. setSleepDurationFormatted के मुख्य हिस्से में, डेटा को व्यू के साथ ठीक उसी तरह बाइंड करें जैसे आपने ViewHolder.bind() में किया था. convertDurationToFormatted() को कॉल करें और फिर TextView के text को फ़ॉर्मैट किए गए टेक्स्ट पर सेट करें. (यह TextView पर एक एक्सटेंशन फ़ंक्शन है, इसलिए आप सीधे text प्रॉपर्टी को ऐक्सेस कर सकते हैं.)
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
  1. इस बाइंडिंग अडैप्टर के बारे में डेटा बाइंडिंग के बारे में बताने के लिए, @BindingAdapter के साथ फ़ंक्शन के बारे में बताएं.
  2. यह फ़ंक्शन sleepDurationFormatted एट्रिब्यूट का अडैप्टर है, इसलिए @BindingAdapter को आर्ग्युमेंट के तौर पर sleepDurationFormatted पास करें.
@BindingAdapter("sleepDurationFormatted")
  1. दूसरा अडैप्टर, SleepNight ऑब्जेक्ट की वैल्यू के हिसाब से नींद की क्वालिटी सेट करता है. TextView पर setSleepQualityString() नाम का एक्सटेंशन फ़ंक्शन बनाएं और SleepNight को पास करें.
  2. मुख्य हिस्से में, डेटा को व्यू में उसी तरह बाइंड करें जैसे आपने ViewHolder.bind() में किया था. convertNumericQualityToString को कॉल करें और text सेट करें.
  3. @BindingAdapter("sleepQualityString") के साथ फ़ंक्शन की व्याख्या करें.
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
   text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
  1. तीसरा बाइंडिंग अडैप्टर, इमेज को इमेज व्यू पर सेट करता है. ImageView पर एक्सटेंशन फ़ंक्शन बनाएं, setSleepImage को कॉल करें, और ViewHolder.bind() के कोड का उपयोग करें, जैसा कि नीचे दिखाया गया है.
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
   setImageResource(when (item.sleepQuality) {
       0 -> R.drawable.ic_sleep_0
       1 -> R.drawable.ic_sleep_1
       2 -> R.drawable.ic_sleep_2
       3 -> R.drawable.ic_sleep_3
       4 -> R.drawable.ic_sleep_4
       5 -> R.drawable.ic_sleep_5
       else -> R.drawable.ic_sleep_active
   })
}

दूसरा चरण: SleepNightAdapter को अपडेट करना

  1. SleepNightAdapter.kt खोलें.
  2. bind() तरीके में मौजूद सब कुछ मिटा दें, क्योंकि अब आप इस काम के लिए डेटा बाइंडिंग और अपने नए अडैप्टर का इस्तेमाल कर सकते हैं.
fun bind(item: SleepNight) {
}
  1. bind() के अंदर, item को स्लीप मोड असाइन करें. ऐसा इसलिए, क्योंकि आपको अपने नए SleepNight के बारे में बाइंडिंग ऑब्जेक्ट बताना होगा.
binding.sleep = item
  1. उस लाइन के नीचे, binding.executePendingBindings() जोड़ें. यह कॉल ऐसा ऑप्टिमाइज़ेशन है जिसमें डेटा बाइंडिंग के दौरान किसी भी ऐसी बाइंडिंग को लागू करने के लिए कहा जाता है जिसे मंज़ूरी मिलना बाकी है. RecyclerView में बाइंडिंग अडैप्टर का इस्तेमाल करते समय, executePendingBindings() को कॉल करना हमेशा एक अच्छा आइडिया है, क्योंकि इससे व्यू का साइज़ तेज़ी से बढ़ सकता है.
 binding.executePendingBindings()

तीसरा चरण: एक्सएमएल लेआउट में बाइंडिंग जोड़ना

  1. list_item_sleep_night.xml खोलें.
  2. ImageView में, इमेज को सेट करने वाले बाइंडिंग अडैप्टर के नाम वाली app प्रॉपर्टी जोड़ें. जैसा कि नीचे दिखाया गया है, sleep वैरिएबल में पास करें.

    यह प्रॉपर्टी, अडैप्टर की मदद से व्यू और बाइंडिंग ऑब्जेक्ट के बीच कनेक्शन बनाती है. जब भी sleepImage को रेफ़र किया जाता है, तो अडैप्टर SleepNight के डेटा को ऑप्टिमाइज़ करेगा.
app:sleepImage="@{sleep}"
  1. sleep_length और quality_string टेक्स्ट व्यू के लिए भी यही करें. जब भी sleepDurationFormatted या sleepQualityString का रेफ़रंस दिया जाता है, तो अडैप्टर SleepNight के डेटा को ऑप्टिमाइज़ कर सकेंगे.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
  1. अपना ऐप्लिकेशन चलाएं. यह पहले की तरह ही काम करता है. बाइंडिंग अडैप्टर, डेटा में बदलाव के साथ-साथ व्यू को फ़ॉर्मैट करने और अपडेट करने का काम करते हैं. इससे, ViewHolder को आसान बनाया जाता है और कोड को पहले के मुकाबले ज़्यादा बेहतर स्ट्रक्चर दिया जाता है.

आपने पिछले कुछ कसरतों के लिए एक ही सूची दिखाई है. यह डिज़ाइन के हिसाब से, आपको यह दिखाता है किAdapter इंटरफ़ेस के ज़रिए आप अपने कोड को कई अलग-अलग तरीकों से बना सकते हैं. आपका कोड जितना मुश्किल होगा, उसे अच्छी तरह से डिज़ाइन करना उतना ही अहम होगा. प्रोडक्शन ऐप्लिकेशन में, इन पैटर्न और अन्य चीज़ों को RecyclerView के साथ इस्तेमाल किया जाता है. सभी पैटर्न काम करते हैं और हर तरीके के अपने फ़ायदे हैं. आप जो भी चुनते हैं वह इस बात पर निर्भर करता है कि आप क्या बना रहे हैं.

बधाई हो! इस समय आप' Android पर RecyclerView में महारत हासिल करने में माहिर हैं.

Android Studio प्रोजेक्ट: RecyclerViewDiffUtilDataBinding.

DiffUtil:

  • RecyclerView के पास DiffUtil नाम की एक क्लास है, जो दो सूचियों के बीच के फ़र्क़ का हिसाब लगाती है.
  • DiffUtil की ItemCallBack नाम की एक क्लास है, जिसे आप दो सूचियों के बीच का अंतर जानने के लिए बढ़ाते हैं.
  • ItemCallback क्लास में, आपको areItemsTheSame() और areContentsTheSame() तरीकों को बदलना होगा.

ListAdapter:

  • अगर आप सूची को मुफ़्त में मैनेज करना चाहते हैं, तो आप RecyclerView.Adapter के बजाय ListAdapter क्लास का इस्तेमाल कर सकते हैं. हालांकि, अगर आप ListAdapter का इस्तेमाल करते हैं, तो आपको अन्य लेआउट के लिए खुद अपना अडैप्टर लिखना होगा. इसलिए, इस कोडलैब में आपको यह करने का तरीका दिखाया गया है.
  • Android Studio में इंटेंट मेन्यू खोलने के लिए, कोड को किसी भी आइटम पर ले जाएं और Alt+Enter (Mac पर Option+Enter) दबाएं. यह मेन्यू खास तौर पर कोड को रीफ़ैक्टर करने और तरीकों को लागू करने के लिए स्टब बनाने में मदद करता है. यह मेन्यू संदर्भ के हिसाब से संवेदनशील है, इसलिए सही मेन्यू पाने के लिए आपको कर्सर सटीक रखना होगा.

डेटा बाइंडिंग:

  • डेटा को व्यू से बाइंड करने के लिए, आइटम लेआउट में डेटा बाइंडिंग का इस्तेमाल करें.

बाइंडिंग अडैप्टर:

  • आपने डेटा का इस्तेमाल करके स्ट्रिंग बनाने के लिए पहले Transformations का इस्तेमाल किया था. अगर आपको अलग-अलग या जटिल तरह के डेटा को बाइंड करना है, तो बाइंडिंग अडैप्टर का इस्तेमाल करें, ताकि डेटा बाइंडिंग का इस्तेमाल किया जा सके.
  • बाइंडिंग अडैप्टर का एलान करने के लिए, एक तरीका बताएं, जो किसी आइटम और व्यू को लेता है. साथ ही, @BindingAdapter के साथ मेथड के बारे में बताएं. Kotlin में, बाइंडिंग अडैप्टर को View पर एक्सटेंशन फ़ंक्शन के तौर पर लिखा जा सकता है. उस प्रॉपर्टी के नाम से पास करें जिसे अडैप्टर अपनाता है. उदाहरण के लिए:
@BindingAdapter("sleepDurationFormatted")
  • एक्सएमएल लेआउट में, बाइंडिंग अडैप्टर के नाम वाली ही एक app प्रॉपर्टी सेट करें. डेटा के साथ एक वैरिएबल में पास करें. उदाहरण के लिए:
.app:sleepDurationFormatted="@{sleep}"

Udcity कोर्स:

Android डेवलपर दस्तावेज़:

अन्य संसाधन:

इस सेक्शन में उन छात्र-छात्राओं के लिए गृहकार्य की असाइनमेंट की सूची दी गई है जो इस कोडलैब के ज़रिए एक शिक्षक की देखरेख में कोर्स में काम कर रहे हैं. यह क्रिएटर का काम #33 पर निर्भर करता है:

  • अगर ज़रूरी हो, तो होमवर्क असाइन करें.
  • छात्र-छात्राओं को होमवर्क के असाइनमेंट सबमिट करने के तरीके के बारे में बताएं.
  • होमवर्क असाइनमेंट को ग्रेड दें.

शिक्षक इन सुझावों का इस्तेमाल जितनी चाहें उतनी कम या ज़्यादा कर सकते हैं. साथ ही, उन्हें अपने हिसाब से कोई भी होमवर्क असाइन करना चाहिए.

अगर आप इस कोडलैब के ज़रिए खुद काम कर रहे हैं, तो बेझिझक इन होमवर्क असाइनमेंट का इस्तेमाल करें.

इन सवालों के जवाब दें

पहला सवाल

DiffUtil का इस्तेमाल करने के लिए, इनमें से क्या ज़रूरी है? लागू होने वाले सभी विकल्प चुनें.

ItemCallBack क्लास बढ़ाएं.

▢ ओवरराइड करें areItemsTheSame().

▢ ओवरराइड करें areContentsTheSame().

▢ आइटम के बीच अंतर को ट्रैक करने के लिए डेटा बाइंडिंग का इस्तेमाल करें.

सवाल 2

बाइंडिंग अडैप्टर के बारे में इनमें से कौनसी बातें सही हैं?

▢ बाइंडिंग अडैप्टर, फ़ंक्शन है जिसे @BindingAdapter के साथ एनोटेट किया गया है.

▢ बाइंडिंग अडैप्टर का इस्तेमाल करने से डेटा फ़ॉर्मैट को व्यू होल्डर से अलग किया जा सकता है.

▢ अगर आप बाइंडिंग अडैप्टर का इस्तेमाल करना चाहते हैं, तो आपको RecyclerViewAdapter का इस्तेमाल करना होगा.

▢ बाइंडिंग अडैप्टर तब अच्छे समाधान होते हैं, जब आपको मुश्किल डेटा को बदलना होता है.

सवाल 3

आपको बाइंडिंग अडैप्टर के बजाय Transformations का इस्तेमाल कब करना चाहिए? लागू होने वाले सभी विकल्प चुनें.

▢ आपका डेटा आसान है.

▢ आप किसी स्ट्रिंग को फ़ॉर्मैट कर रहे हैं.

▢ आपकी सूची बहुत लंबी है.

ViewHolder में सिर्फ़ एक व्यू है.

अगला लेसन शुरू करें: 7.3: RecyclerView के साथ GridLayout