यह कोडलैब, Android Kotlin Fundamentals कोर्स का हिस्सा है. अगर कोडलैब को क्रम से पूरा किया जाता है, तो आपको इस कोर्स से सबसे ज़्यादा फ़ायदा मिलेगा. कोर्स के सभी कोडलैब, Android Kotlin Fundamentals कोडलैब के लैंडिंग पेज पर दिए गए हैं.
शुरुआती जानकारी
पिछले कोडलैब में, आपने वेब सेवा से डेटा पाने और जवाब को डेटा ऑब्जेक्ट में पार्स करने का तरीका सीखा था. इस कोडलैब में, आपको उस जानकारी का इस्तेमाल करके, वेब यूआरएल से फ़ोटो लोड करने और उन्हें दिखाने के बारे में बताया गया है. आपको यह भी बताया जाएगा कि RecyclerView कैसे बनाया जाता है और इसका इस्तेमाल, खास जानकारी वाले पेज पर इमेज की ग्रिड दिखाने के लिए कैसे किया जाता है.
आपको पहले से क्या पता होना चाहिए
- फ़्रैगमेंट बनाने और इस्तेमाल करने का तरीका.
- व्यू मॉडल, व्यू मॉडल फ़ैक्ट्री, ट्रांसफ़ॉर्मेशन, और
LiveDataजैसे आर्किटेक्चर कॉम्पोनेंट का इस्तेमाल कैसे करें. - REST वेब सेवा से JSON को कैसे वापस पाएं और Retrofit और Moshi लाइब्रेरी का इस्तेमाल करके, उस डेटा को Kotlin ऑब्जेक्ट में कैसे पार्स करें.
RecyclerViewकी मदद से ग्रिड लेआउट बनाने का तरीका.Adapter,ViewHolder, औरDiffUtilके काम करने का तरीका.
आपको क्या सीखने को मिलेगा
- वेब यूआरएल से इमेज लोड करने और उसे दिखाने के लिए, Glide लाइब्रेरी का इस्तेमाल कैसे करें.
- इमेज की ग्रिड दिखाने के लिए,
RecyclerViewऔर ग्रिड अडैप्टर का इस्तेमाल करने का तरीका. - इमेज डाउनलोड और डिसप्ले होने के दौरान, संभावित गड़बड़ियों को कैसे ठीक करें.
आपको क्या करना होगा
- MarsRealEstate ऐप्लिकेशन में बदलाव करें, ताकि मंगल ग्रह की प्रॉपर्टी के डेटा से इमेज का यूआरएल मिल सके. साथ ही, Glide का इस्तेमाल करके उस इमेज को लोड और दिखाया जा सके.
- ऐप्लिकेशन में लोडिंग ऐनिमेशन और गड़बड़ी का आइकॉन जोड़ें.
- मंगल ग्रह की प्रॉपर्टी की इमेज का ग्रिड दिखाने के लिए,
RecyclerViewका इस्तेमाल करें. RecyclerViewमें स्थिति और गड़बड़ी को मैनेज करने की सुविधा जोड़ें.
इस कोडलैब (और इससे जुड़े कोडलैब) में, आपको MarsRealEstate नाम के ऐप्लिकेशन के साथ काम करना है. यह ऐप्लिकेशन, मंगल ग्रह पर बिक्री के लिए उपलब्ध प्रॉपर्टी दिखाता है. यह ऐप्लिकेशन, इंटरनेट सर्वर से कनेक्ट होता है. इससे प्रॉपर्टी का डेटा वापस पाने और उसे दिखाने में मदद मिलती है. इसमें कीमत और प्रॉपर्टी बिक्री या किराये के लिए उपलब्ध है या नहीं, जैसी जानकारी शामिल होती है. हर प्रॉपर्टी को दिखाने वाली इमेज, मंगल ग्रह की असली फ़ोटो हैं. इन्हें नासा के मार्स रोवर ने कैप्चर किया है.

इस कोडलैब में बनाया गया ऐप्लिकेशन, खास जानकारी वाले पेज पर दिखता है. इस पेज पर इमेज की ग्रिड दिखती है. ये इमेज, प्रॉपर्टी के उस डेटा का हिस्सा हैं जो आपका ऐप्लिकेशन, Mars real estate की वेब सेवा से पाता है. आपका ऐप्लिकेशन, Glide लाइब्रेरी का इस्तेमाल करके इमेज लोड करेगा और उन्हें दिखाएगा. साथ ही, इमेज के लिए ग्रिड लेआउट बनाने के लिए RecyclerView का इस्तेमाल करेगा. आपका ऐप्लिकेशन, नेटवर्क से जुड़ी गड़बड़ियों को भी आसानी से ठीक कर पाएगा.
किसी वेब यूआरएल से फ़ोटो दिखाना आसान लग सकता है, लेकिन इसे ठीक से काम करने के लिए काफ़ी इंजीनियरिंग की ज़रूरत होती है. इमेज को कंप्रेस किए गए फ़ॉर्मैट से डाउनलोड, बफ़र, और डिकोड किया जाता है, ताकि Android उसका इस्तेमाल कर सके. इमेज को इन-मेमोरी कैश, स्टोरेज-आधारित कैश या दोनों में से किसी एक में कैश किया जाना चाहिए. यह सब कम प्राथमिकता वाली बैकग्राउंड थ्रेड में होना चाहिए, ताकि यूज़र इंटरफ़ेस (यूआई) रिस्पॉन्सिव बना रहे. इसके अलावा, नेटवर्क और सीपीयू की बेहतर परफ़ॉर्मेंस के लिए, एक से ज़्यादा इमेज को एक साथ फ़ेच और डिकोड किया जा सकता है. नेटवर्क से इमेज को असरदार तरीके से लोड करने का तरीका, एक कोडलैब हो सकता है.
अच्छी बात यह है कि इमेज डाउनलोड करने, बफ़र करने, डिकोड करने, और कैश मेमोरी में सेव करने के लिए, Glide नाम की लाइब्रेरी का इस्तेमाल किया जा सकता है. इसे कम्यूनिटी ने बनाया है. Glide की मदद से, आपको शुरू से यह सब करने की ज़रूरत नहीं पड़ती.
Glide को बुनियादी तौर पर दो चीज़ों की ज़रूरत होती है:
- उस इमेज का यूआरएल जिसे लोड और दिखाना है.
- उस इमेज को दिखाने के लिए,
ImageViewऑब्जेक्ट.
इस टास्क में, आपको Glide का इस्तेमाल करके, रियल एस्टेट की वेब सेवा से एक इमेज दिखाने का तरीका बताया गया है. आपको उस इमेज को दिखाना होगा जो वेब सेवा से मिली प्रॉपर्टी की सूची में, मंगल ग्रह की पहली प्रॉपर्टी को दिखाती है. यहां पहले और बाद के स्क्रीनशॉट दिए गए हैं:


पहला चरण: Glide डिपेंडेंसी जोड़ना
- पिछले कोडलैब से MarsRealEstate ऐप्लिकेशन खोलें. (अगर आपके पास यह ऐप्लिकेशन नहीं है, तो MarsRealEstateNetwork को यहां से डाउनलोड किया जा सकता है.)
- ऐप्लिकेशन को चलाकर देखें कि यह क्या काम करता है. (इसमें मंगल ग्रह पर मौजूद किसी प्रॉपर्टी की जानकारी दिखाई गई है.)
- build.gradle (Module: app) खोलें.
dependenciesसेक्शन में, Glide लाइब्रेरी के लिए यह लाइन जोड़ें:
implementation "com.github.bumptech.glide:glide:$version_glide"
ध्यान दें कि वर्शन नंबर, प्रोजेक्ट की Gradle फ़ाइल में पहले से ही अलग से तय किया गया है.
- नई डिपेंडेंसी के साथ प्रोजेक्ट को फिर से बनाने के लिए, अभी सिंक करें पर क्लिक करें.
दूसरा चरण: व्यू मॉडल अपडेट करना
इसके बाद, आपको OverviewViewModel क्लास को अपडेट करना होगा, ताकि उसमें मंगल ग्रह की किसी एक प्रॉपर्टी का लाइव डेटा शामिल किया जा सके.
overview/OverviewViewModel.ktखोलें._responseके ठीक नीचे, एक हीMarsPropertyऑब्जेक्ट के लिए, इंटरनल (बदला जा सकने वाला) और एक्सटर्नल (बदला नहीं जा सकने वाला) लाइव डेटा, दोनों जोड़ें.LiveData
जब अनुरोध किया जाए, तबMarsPropertyक्लास (com.example.android.marsrealestate.network.MarsProperty) इंपोर्ट करें.
private val _property = MutableLiveData<MarsProperty>()
val property: LiveData<MarsProperty>
get() = _propertygetMarsRealEstateProperties()तरीके में,try/catch {}ब्लॉक के अंदर मौजूद वह लाइन ढूंढें जो_response.valueको प्रॉपर्टी की संख्या पर सेट करती है. नीचे दिखाया गया टेस्ट जोड़ें. अगरMarsPropertyऑब्जेक्ट उपलब्ध हैं, तो यह टेस्ट_propertyLiveDataकी वैल्यू कोlistResultमें मौजूद पहली प्रॉपर्टी पर सेट करता है.
if (listResult.size > 0) {
_property.value = listResult[0]
}पूरा try/catch {} ब्लॉक अब ऐसा दिखता है:
try {
var listResult = getPropertiesDeferred.await()
_response.value = "Success: ${listResult.size} Mars properties retrieved"
if (listResult.size > 0) {
_property.value = listResult[0]
}
} catch (e: Exception) {
_response.value = "Failure: ${e.message}"
}res/layout/fragment_overview.xmlफ़ाइल खोलें.<TextView>एलिमेंट में,android:textको बदलकरpropertyLiveDataकेimgSrcUrlकॉम्पोनेंट से बाइंड करें:
android:text="@{viewModel.property.imgSrcUrl}"- ऐप्लिकेशन चलाएं.
TextView, Mars की पहली प्रॉपर्टी में मौजूद इमेज का यूआरएल दिखाता है. अब तक आपने सिर्फ़ व्यू मॉडल और उस यूआरएल के लिए लाइव डेटा सेट अप किया है.

तीसरा चरण: बाइंडिंग अडैप्टर बनाना और Glide को कॉल करना
अब आपके पास डिसप्ले करने के लिए इमेज का यूआरएल है. अब Glide का इस्तेमाल करके, उस इमेज को लोड करने का समय है. इस चरण में, बाइंडिंग अडैप्टर का इस्तेमाल करके, ImageView से जुड़े एक्सएमएल एट्रिब्यूट से यूआरएल लिया जाता है. साथ ही, Glide का इस्तेमाल करके इमेज लोड की जाती है. बाइंडिंग अडैप्टर, एक्सटेंशन मेथड होते हैं. ये व्यू और बाउंड डेटा के बीच मौजूद होते हैं. इनका काम, डेटा में बदलाव होने पर कस्टम व्यवहार दिखाना होता है. इस मामले में, कस्टम व्यवहार यह है कि Glide को कॉल करके, यूआरएल से इमेज को ImageView में लोड किया जाए.
BindingAdapters.ktखोलें. इस फ़ाइल में, ऐप्लिकेशन में इस्तेमाल किए जाने वाले बाइंडिंग अडैप्टर मौजूद होंगे.- एक
bindImage()फ़ंक्शन बनाएं, जोImageViewऔरStringको पैरामीटर के तौर पर इस्तेमाल करे. फ़ंक्शन को@BindingAdapterसे एनोटेट करें.@BindingAdapterएनोटेशन, डेटा बाइंडिंग को बताता है कि जब किसी एक्सएमएल आइटम मेंimageUrlएट्रिब्यूट मौजूद हो, तब आपको इस बाइंडिंग अडैप्टर को एक्ज़ीक्यूट करना है.
अनुरोध किए जाने पर,androidx.databinding.BindingAdapterऔरandroid.widget.ImageViewइंपोर्ट करें.
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView, imgUrl: String?) {
}bindImage()फ़ंक्शन में,imgUrlआर्ग्युमेंट के लिएlet {}ब्लॉक जोड़ें:
imgUrl?.let {
}let {}ब्लॉक में, नीचे दी गई लाइन जोड़ें. इससे यूआरएल स्ट्रिंग (एक्सएमएल से) कोUriऑब्जेक्ट में बदला जा सकेगा. अनुरोध किए जाने परandroidx.core.net.toUriइंपोर्ट करें.
आपको फ़ाइनलUriऑब्जेक्ट के लिए एचटीटीपीएस स्कीम का इस्तेमाल करना है, क्योंकि जिस सर्वर से इमेज ली जाती हैं उसके लिए इस स्कीम की ज़रूरत होती है. एचटीटीपीएस स्कीम का इस्तेमाल करने के लिए,toUriबिल्डर मेंbuildUpon.scheme("https")जोड़ें.toUri()तरीका, Android KTX की कोर लाइब्रेरी का Kotlin एक्सटेंशन फ़ंक्शन है. इसलिए, यह सिर्फ़Stringक्लास का हिस्सा दिखता है.
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()- अब भी
let {}के अंदर,Glide.with()को कॉल करें, ताकिUriऑब्जेक्ट से इमेज कोImageViewमें लोड किया जा सके. अनुरोध किए जाने पर,com.bumptech.glide.Glideइंपोर्ट करें.
Glide.with(imgView.context)
.load(imgUri)
.into(imgView)चौथा चरण: लेआउट और फ़्रैगमेंट अपडेट करना
Glide ने इमेज लोड कर दी है, लेकिन अभी कुछ भी नहीं दिख रहा है. इसके बाद, इमेज दिखाने के लिए लेआउट और फ़्रैगमेंट को ImageView से अपडेट करें.
res/layout/gridview_item.xmlखोलें. यह लेआउट रिसॉर्स फ़ाइल है. इसका इस्तेमाल, कोडलैब में बाद मेंRecyclerViewके हर आइटम के लिए किया जाएगा. इसका इस्तेमाल यहां सिर्फ़ एक इमेज दिखाने के लिए किया जाता है.- डेटा बाइंडिंग के लिए,
<ImageView>एलिमेंट के ऊपर<data>एलिमेंट जोड़ें. इसके बाद, इसेOverviewViewModelक्लास से बाइंड करें:
<data>
<variable
name="viewModel"
type="com.example.android.marsrealestate.overview.OverviewViewModel" />
</data>- नई इमेज लोडिंग बाइंडिंग अडैप्टर का इस्तेमाल करने के लिए,
ImageViewएलिमेंट मेंapp:imageUrlएट्रिब्यूट जोड़ें:
app:imageUrl="@{viewModel.property.imgSrcUrl}"overview/OverviewFragment.ktखोलें.onCreateView()तरीके में, उस लाइन पर टिप्पणी करें जोFragmentOverviewBindingक्लास को बढ़ाती है और उसे बाइंडिंग वैरिएबल को असाइन करती है. यह सिर्फ़ कुछ समय के लिए है. बाद में आपको यह सुविधा फिर से मिल जाएगी.
//val binding = FragmentOverviewBinding.inflate(inflater)- इसके बजाय,
GridViewItemBindingक्लास को बड़ा करने के लिए एक लाइन जोड़ें. अनुरोध किए जाने पर,com.example.android.marsrealestate. databinding.GridViewItemBindingइंपोर्ट करें.
val binding = GridViewItemBinding.inflate(inflater)- ऐप्लिकेशन चलाएं. अब आपको नतीजों की सूची में, पहले
MarsPropertyकी इमेज की फ़ोटो दिखेगी.
पांचवां चरण: सामान्य लोडिंग और गड़बड़ी की इमेज जोड़ना
Glide, इमेज लोड होने के दौरान प्लेसहोल्डर इमेज दिखा सकता है. साथ ही, इमेज लोड न होने पर गड़बड़ी वाली इमेज दिखा सकता है. इससे उपयोगकर्ता अनुभव को बेहतर बनाया जा सकता है. उदाहरण के लिए, अगर इमेज मौजूद नहीं है या खराब हो गई है, तो ऐसा हो सकता है. इस चरण में, बाइंडिंग अडैप्टर और लेआउट में यह सुविधा जोड़ी जाती है.
res/drawable/ic_broken_image.xmlखोलें और दाईं ओर मौजूद, झलक देखें टैब पर क्लिक करें. गड़बड़ी वाली इमेज के लिए, आपने टूटी हुई इमेज वाले आइकॉन का इस्तेमाल किया है. यह आइकॉन, पहले से मौजूद आइकॉन लाइब्रेरी में उपलब्ध है. इस वेक्टर ड्रॉएबल में,android:tintएट्रिब्यूट का इस्तेमाल करके आइकॉन को ग्रे रंग में दिखाया गया है.

res/drawable/loading_animation.xmlखोलें. यह ड्रॉ करने लायक एक ऐनिमेशन है, जिसे<animate-rotate>टैग के साथ तय किया गया है. यह ऐनिमेशन, इमेज ड्रॉएबलloading_img.xmlको बीच के पॉइंट के चारों ओर घुमाता है. (आपको झलक में ऐनिमेशन नहीं दिखता.)

BindingAdapters.ktफ़ाइल पर वापस जाएं.bindImage()तरीके में,Glide.with()को कॉल करने के लिए अपडेट करें, ताकिload()औरinto()के बीचapply()फ़ंक्शन को कॉल किया जा सके. अनुरोध किए जाने परcom.bumptech.glide.request.RequestOptionsइंपोर्ट करें.
यह कोड, लोड होने के दौरान इस्तेमाल की जाने वाली प्लेसहोल्डर इमेज सेट करता है (loading_animationड्रॉएबल). अगर इमेज लोड नहीं होती है, तो कोड एक इमेज सेट करता है. इस इमेज का इस्तेमाल किया जाता है (broken_imageड्रॉएबल).bindImage()तरीका अब ऐसा दिखता है:
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView, imgUrl: String?) {
imgUrl?.let {
val imgUri =
imgUrl.toUri().buildUpon().scheme("https").build()
Glide.with(imgView.context)
.load(imgUri)
.apply(RequestOptions()
.placeholder(R.drawable.loading_animation)
.error(R.drawable.ic_broken_image))
.into(imgView)
}
}
- ऐप्लिकेशन चलाएं. आपके नेटवर्क कनेक्शन की स्पीड के हिसाब से, आपको कुछ समय के लिए लोडिंग इमेज दिख सकती है. ऐसा तब होता है, जब Glide प्रॉपर्टी की इमेज डाउनलोड करके दिखाता है. हालांकि, नेटवर्क बंद करने पर भी आपको अब तक टूटी हुई इमेज का आइकॉन नहीं दिखेगा. इसे ठीक करने का तरीका, कोडलैब के आखिरी हिस्से में बताया गया है.
अब आपका ऐप्लिकेशन, इंटरनेट से प्रॉपर्टी की जानकारी लोड करता है. आपने पहले MarsProperty सूची आइटम से मिले डेटा का इस्तेमाल करके, व्यू मॉडल में LiveData प्रॉपर्टी बनाई है. साथ ही, आपने उस प्रॉपर्टी के डेटा से मिले इमेज यूआरएल का इस्तेमाल करके, ImageView को भरा है. हालांकि, आपका लक्ष्य यह है कि आपका ऐप्लिकेशन इमेज का ग्रिड दिखाए. इसलिए, आपको GridLayoutManager के साथ RecyclerView का इस्तेमाल करना होगा.
पहला चरण: व्यू मॉडल अपडेट करना
फ़िलहाल, व्यू मॉडल में एक _property LiveData है, जिसमें एक MarsProperty ऑब्जेक्ट है. यह वेब सेवा से मिले रिस्पॉन्स की सूची में पहला ऑब्जेक्ट है. इस चरण में, LiveData को बदलकर MarsProperty ऑब्जेक्ट की पूरी सूची को शामिल किया जाता है.
overview/OverviewViewModel.ktखोलें.- निजी
_propertyवैरिएबल को_propertiesमें बदलें. टाइप कोMarsPropertyऑब्जेक्ट की सूची में बदलें.
private val _properties = MutableLiveData<List<MarsProperty>>()- बाहरी
propertyलाइव डेटा कोpropertiesसे बदलें. इस सूची को यहां भीLiveDataटाइप में जोड़ें:
val properties: LiveData<List<MarsProperty>>
get() = _properties- नीचे की ओर स्क्रोल करके,
getMarsRealEstateProperties()तरीके पर जाएं.try {}ब्लॉक में, पिछले टास्क में जोड़े गए पूरे टेस्ट को नीचे दी गई लाइन से बदलें.listResultवैरिएबल मेंMarsPropertyऑब्जेक्ट की सूची होती है. इसलिए, आपको_properties.valueको सिर्फ़ इसे असाइन करना होगा. इसके लिए, आपको यह जांच करने की ज़रूरत नहीं है कि रिस्पॉन्स सही है या नहीं.
_properties.value = listResultपूरा try/catch ब्लॉक अब ऐसा दिखता है:
try {
var listResult = getPropertiesDeferred.await()
_response.value = "Success: ${listResult.size} Mars properties retrieved"
_properties.value = listResult
} catch (e: Exception) {
_response.value = "Failure: ${e.message}"
}दूसरा चरण: लेआउट और फ़्रैगमेंट अपडेट करना
अगला चरण, ऐप्लिकेशन के लेआउट और फ़्रैगमेंट को बदलना है, ताकि सिंगल इमेज व्यू के बजाय रीसाइकलर व्यू और ग्रिड लेआउट का इस्तेमाल किया जा सके.
res/layout/gridview_item.xmlखोलें. डेटा बाइंडिंग कोOverviewViewModelसे बदलकरMarsPropertyकरें. साथ ही, वैरिएबल का नाम बदलकर"property"करें.
<variable
name="property"
type="com.example.android.marsrealestate.network.MarsProperty" /><ImageView>में,app:imageUrlएट्रिब्यूट को बदलकर,MarsPropertyऑब्जेक्ट में मौजूद इमेज के यूआरएल का रेफ़रंस दें:
app:imageUrl="@{property.imgSrcUrl}"overview/OverviewFragment.ktखोलें.onCreateview()में,FragmentOverviewBindingको बढ़ाने वाली लाइन से टिप्पणी हटाएं.GridViewBindingको बढ़ाने वाली लाइन को मिटाएं या उस पर टिप्पणी करें. इन बदलावों से, पिछले टास्क में किए गए अस्थायी बदलावों को पहले जैसा कर दिया जाता है.
val binding = FragmentOverviewBinding.inflate(inflater)
// val binding = GridViewItemBinding.inflate(inflater)res/layout/fragment_overview.xmlखोलें. पूरे<TextView>एलिमेंट को मिटाएं.- इसके बजाय, यह
<RecyclerView>एलिमेंट जोड़ें. यह एक आइटम के लिए,GridLayoutManagerऔरgrid_view_itemलेआउट का इस्तेमाल करता है:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/photos_grid"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="6dp"
android:clipToPadding="false"
app:layoutManager=
"androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:spanCount="2"
tools:itemCount="16"
tools:listitem="@layout/grid_view_item" />तीसरा चरण: फ़ोटो ग्रिड अडैप्टर जोड़ना
अब fragment_overview लेआउट में एक RecyclerView है, जबकि grid_view_item लेआउट में एक ImageView है. इस चरण में, RecyclerView अडैप्टर के ज़रिए डेटा को RecyclerView से बाइंड किया जाता है.
overview/PhotoGridAdapter.ktखोलें.- नीचे दिए गए कंस्ट्रक्टर पैरामीटर के साथ
PhotoGridAdapterक्लास बनाएं.PhotoGridAdapterक्लास,ListAdapterको बढ़ाता है. इसके कंस्ट्रक्टर को लिस्ट आइटम टाइप, व्यू होल्डर, औरDiffUtil.ItemCallbackलागू करने की ज़रूरत होती है.
अनुरोध किए जाने पर,androidx.recyclerview.widget.ListAdapterऔरcom.example.android.marsrealestate.network.MarsPropertyक्लास इंपोर्ट करें. यहां दिए गए तरीके में, इस कंस्ट्रक्टर के अन्य छूटे हुए हिस्सों को लागू किया जाता है. इससे गड़बड़ियां ठीक हो जाती हैं.
class PhotoGridAdapter : ListAdapter<MarsProperty,
PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {
}PhotoGridAdapterक्लास में कहीं भी क्लिक करें औरControl+iदबाकरListAdapterतरीकों को लागू करें. ये तरीकेonCreateViewHolder()औरonBindViewHolder()हैं.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoGridAdapter.MarsPropertyViewHolder {
TODO("not implemented")
}
override fun onBindViewHolder(holder: PhotoGridAdapter.MarsPropertyViewHolder, position: Int) {
TODO("not implemented")
}PhotoGridAdapterक्लास की परिभाषा के आखिर में, अभी जोड़े गए तरीकों के बाद,DiffCallbackके लिए कंपैनियन ऑब्जेक्ट की परिभाषा जोड़ें. इसे नीचे दिखाया गया है.
अनुरोध किए जाने परandroidx.recyclerview.widget.DiffUtilइंपोर्ट करें.DiffCallbackऑब्जेक्ट,DiffUtil.ItemCallbackको उस ऑब्जेक्ट के टाइप के साथ बढ़ाता है जिससे आपको तुलना करनी है—MarsProperty.
companion object DiffCallback : DiffUtil.ItemCallback<MarsProperty>() {
}- इस ऑब्जेक्ट के लिए, तुलना करने के तरीके लागू करने के लिए
Control+iदबाएं. ये तरीकेareItemsTheSame()औरareContentsTheSame()हैं.
override fun areItemsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
TODO("not implemented")
}
override fun areContentsTheSame(oldItem: MarsProperty, newItem: MarsProperty): Boolean {
TODO("not implemented") }areItemsTheSame()तरीके के लिए, TODO हटाएं. Kotlin के रेफ़रेंशियल इक्वैलिटी ऑपरेटर (===) का इस्तेमाल करें. यह ऑपरेटर,oldItemऔरnewItemके लिए ऑब्जेक्ट रेफ़रंस एक ही होने परtrueदिखाता है.
override fun areItemsTheSame(oldItem: MarsProperty,
newItem: MarsProperty): Boolean {
return oldItem === newItem
}areContentsTheSame()के लिए,oldItemऔरnewItemके सिर्फ़ आईडी पर स्टैंडर्ड इक्वैलिटी ऑपरेटर का इस्तेमाल करें.
override fun areContentsTheSame(oldItem: MarsProperty,
newItem: MarsProperty): Boolean {
return oldItem.id == newItem.id
}- अब भी
PhotoGridAdapterक्लास में, कंपैनियन ऑब्जेक्ट के नीचे,MarsPropertyViewHolderके लिए इनर क्लास की परिभाषा जोड़ें. यहRecyclerView.ViewHolderसे एक्सटेंड होती है.
जब अनुरोध किया जाए, तबandroidx.recyclerview.widget.RecyclerViewऔरcom.example.android.marsrealestate.databinding.GridViewItemBindingइंपोर्ट करें.
आपको लेआउट मेंMarsPropertyको बाइंड करने के लिए,GridViewItemBindingवैरिएबल की ज़रूरत होगी. इसलिए, वैरिएबल कोMarsPropertyViewHolderमें पास करें. बेसViewHolderक्लास को अपने कंस्ट्रक्टर में व्यू की ज़रूरत होती है. इसलिए, इसे बाइंडिंग रूट व्यू पास किया जाता है.
class MarsPropertyViewHolder(private var binding:
GridViewItemBinding):
RecyclerView.ViewHolder(binding.root) {
}MarsPropertyViewHolderमें, एकbind()तरीका बनाएं. यहMarsPropertyऑब्जेक्ट को आर्ग्युमेंट के तौर पर लेता है औरbinding.propertyको उस ऑब्जेक्ट पर सेट करता है. प्रॉपर्टी सेट करने के बाद,executePendingBindings()को कॉल करें. इससे अपडेट तुरंत लागू हो जाएगा.
fun bind(marsProperty: MarsProperty) {
binding.property = marsProperty
binding.executePendingBindings()
}onCreateViewHolder()में, TODO को हटाएं और यहां दिखाई गई लाइन जोड़ें. अनुरोध किए जाने पर,android.view.LayoutInflaterइंपोर्ट करें.onCreateViewHolder()तरीके को एक नयाMarsPropertyViewHolderवापस करना होगा. इसेGridViewItemBindingको बड़ा करके और पैरंटViewGroupकॉन्टेक्स्ट सेLayoutInflaterका इस्तेमाल करके बनाया जाता है.
return MarsPropertyViewHolder(GridViewItemBinding.inflate(
LayoutInflater.from(parent.context)))onBindViewHolder()तरीके में, TODO को हटाएं और नीचे दी गई लाइनें जोड़ें. यहांgetItem()को कॉल करके, मौजूदाRecyclerViewपोज़िशन से जुड़ाMarsPropertyऑब्जेक्ट मिलता है. इसके बाद, उस प्रॉपर्टी कोMarsPropertyViewHolderमें मौजूदbind()तरीके से पास किया जाता है.
val marsProperty = getItem(position)
holder.bind(marsProperty)चौथा चरण: बाइंडिंग अडैप्टर जोड़ना और हिस्सों को कनेक्ट करना
आखिर में, MarsProperty ऑब्जेक्ट की सूची के साथ PhotoGridAdapter को शुरू करने के लिए, BindingAdapter का इस्तेमाल करें. RecyclerView डेटा सेट करने के लिए BindingAdapter का इस्तेमाल करने से, डेटा बाइंडिंग अपने-आप MarsProperty ऑब्जेक्ट की सूची के लिए LiveData को मॉनिटर करती है. इसके बाद, MarsProperty सूची में बदलाव होने पर, बाइंडिंग अडैप्टर अपने-आप कॉल हो जाता है.
BindingAdapters.ktखोलें.- फ़ाइल के आखिर में, एक
bindRecyclerView()तरीका जोड़ें. यहRecyclerViewऔरMarsPropertyऑब्जेक्ट की सूची को आर्ग्युमेंट के तौर पर लेता है. उस तरीके को@BindingAdapterके साथ एनोटेट करें.
अनुरोध किए जाने पर,androidx.recyclerview.widget.RecyclerViewऔरcom.example.android.marsrealestate.network.MarsPropertyइंपोर्ट करें.
@BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView,
data: List<MarsProperty>?) {
}bindRecyclerView()फ़ंक्शन में,recyclerView.adapterकोPhotoGridAdapterमें बदलें. इसके बाद, डेटा के साथadapter.submitList()को कॉल करें. इससेRecyclerViewको पता चलता है कि नई सूची कब उपलब्ध है.
अनुरोध किए जाने पर, com.example.android.marsrealestate.overview.PhotoGridAdapter इंपोर्ट करें.
val adapter = recyclerView.adapter as PhotoGridAdapter
adapter.submitList(data)res/layout/fragment_overview.xmlखोलें.RecyclerViewएलिमेंट मेंapp:listDataएट्रिब्यूट जोड़ें और डेटा बाइंडिंग का इस्तेमाल करके, इसेviewmodel.propertiesपर सेट करें.
app:listData="@{viewModel.properties}"overview/OverviewFragment.ktखोलें.onCreateView()में,setHasOptionsMenu()को कॉल करने से ठीक पहले,binding.photosGridमेंRecyclerViewअडैप्टर को नएPhotoGridAdapterऑब्जेक्ट के तौर पर शुरू करें.
binding.photosGrid.adapter = PhotoGridAdapter()- ऐप्लिकेशन चलाएं. आपको
MarsPropertyइमेज का ग्रिड दिखेगा. नई इमेज देखने के लिए स्क्रोल करते समय, ऐप्लिकेशन इमेज दिखाने से पहले लोडिंग-प्रोग्रेस आइकॉन दिखाता है. एयरप्लेन मोड चालू करने पर, जो इमेज अभी तक लोड नहीं हुई हैं वे टूटी हुई इमेज के आइकॉन के तौर पर दिखती हैं.

MarsRealEstate ऐप्लिकेशन, इमेज फ़ेच न हो पाने पर टूटी हुई इमेज का आइकॉन दिखाता है. हालांकि, नेटवर्क न होने पर ऐप्लिकेशन में खाली स्क्रीन दिखती है.

इससे उपयोगकर्ताओं को अच्छा अनुभव नहीं मिलता. इस टास्क में, गड़बड़ी को हैंडल करने की बुनियादी सुविधा जोड़ी जाती है, ताकि उपयोगकर्ता को यह बेहतर तरीके से पता चल सके कि क्या हो रहा है. अगर इंटरनेट उपलब्ध नहीं है, तो ऐप्लिकेशन में कनेक्शन से जुड़ी गड़बड़ी का आइकॉन दिखेगा. ऐप्लिकेशन, MarsProperty की सूची फ़ेच करते समय, लोडिंग ऐनिमेशन दिखाएगा.
पहला चरण: व्यू मॉडल में स्टेटस जोड़ना
शुरू करने के लिए, वेब अनुरोध की स्थिति दिखाने के लिए व्यू मॉडल में LiveData बनाएं. तीन स्थितियां होती हैं: लोड हो रहा है, लोड हो गया है, और लोड नहीं हो सका. लोडिंग की स्थिति तब होती है, जब कॉल में डेटा के लिए इंतज़ार किया जा रहा हो await().
overview/OverviewViewModel.ktखोलें. फ़ाइल में सबसे ऊपर (इंपोर्ट के बाद, क्लास डेफ़िनिशन से पहले), सभी उपलब्ध स्टेटस दिखाने के लिएenumजोड़ें:
enum class MarsApiStatus { LOADING, ERROR, DONE }- पूरी
OverviewViewModelक्लास में, इंटरनल और एक्सटर्नल, दोनों तरह के_responseलाइव डेटा डेफ़िनिशन का नाम बदलकर_statusकरें. आपने इस कोडलैब में पहले ही_propertiesLiveDataके लिए सहायता जोड़ी थी. इसलिए, वेब सेवा के पूरे जवाब का इस्तेमाल नहीं किया गया है. मौजूदा स्थिति को ट्रैक करने के लिए, आपको यहांLiveDataकी ज़रूरत होगी. इसलिए, मौजूदा वैरिएबल का नाम बदला जा सकता है.
साथ ही, टाइप को String से बदलकर MarsApiStatus. करें
private val _status = MutableLiveData<MarsApiStatus>()
val status: LiveData<MarsApiStatus>
get() = _status- नीचे की ओर स्क्रोल करके
getMarsRealEstateProperties()तरीके पर जाएं और यहां भी_responseको_statusपर अपडेट करें."Success"स्ट्रिंग कोMarsApiStatus.DONEस्थिति में और"Failure"स्ट्रिंग कोMarsApiStatus.ERRORस्थिति में बदलें. await()को कॉल करने से पहले,try {}ब्लॉक के सबसे ऊपरMarsApiStatus.LOADINGस्टेटस जोड़ें. यह शुरुआती स्टेटस है. यह तब दिखता है, जब कोरूटीन चल रहा हो और डेटा का इंतज़ार किया जा रहा हो. पूराtry/catch {}ब्लॉक अब ऐसा दिखता है:
try {
_status.value = MarsApiStatus.LOADING
var listResult = getPropertiesDeferred.await()
_status.value = MarsApiStatus.DONE
_properties.value = listResult
} catch (e: Exception) {
_status.value = MarsApiStatus.ERROR
}catch {}ब्लॉक में गड़बड़ी की स्थिति के बाद,_propertiesLiveDataको खाली सूची पर सेट करें. इससेRecyclerViewमिट जाता है.
} catch (e: Exception) {
_status.value = MarsApiStatus.ERROR
_properties.value = ArrayList()
}दूसरा चरण: स्टेटस ImageView के लिए बाइंडिंग अडैप्टर जोड़ना
अब आपके पास व्यू मॉडल में एक स्टेटस है, लेकिन यह सिर्फ़ स्टेटस का एक सेट है. इसे ऐप्लिकेशन में ही कैसे दिखाया जाता है? इस चरण में, डेटा बाइंडिंग से कनेक्ट किए गए ImageView का इस्तेमाल करके, लोडिंग और गड़बड़ी की स्थितियों के लिए आइकॉन दिखाए जाते हैं. जब ऐप्लिकेशन लोड हो रहा हो या उसमें कोई गड़बड़ी हो, तब ImageView दिखना चाहिए. ऐप्लिकेशन लोड होने के बाद, ImageView नहीं दिखना चाहिए.
BindingAdapters.ktखोलें.bindStatus()नाम का एक नया बाइंडिंग अडैप्टर जोड़ें. यहImageViewऔरMarsApiStatusवैल्यू को आर्ग्युमेंट के तौर पर लेता है. अनुरोध किए जाने पर,com.example.android.marsrealestate.overview.MarsApiStatusइंपोर्ट करें.
@BindingAdapter("marsApiStatus")
fun bindStatus(statusImageView: ImageView,
status: MarsApiStatus?) {
}- अलग-अलग स्टेटस के बीच स्विच करने के लिए,
bindStatus()तरीके मेंwhen {}जोड़ें.
when (status) {
}when {}के अंदर, लोडिंग की स्थिति (MarsApiStatus.LOADING) के लिए एक केस जोड़ें. इस स्थिति के लिए,ImageViewको 'दिख रहा है' पर सेट करें और इसे लोडिंग ऐनिमेशन असाइन करें. यह वही ऐनिमेशन ड्रॉएबल है जिसका इस्तेमाल आपने पिछले टास्क में Glide के लिए किया था. अनुरोध किए जाने पर,android.view.Viewइंपोर्ट करें.
when (status) {
MarsApiStatus.LOADING -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.loading_animation)
}
}- गड़बड़ी की स्थिति के लिए एक केस जोड़ें, जो कि
MarsApiStatus.ERRORहै.LOADINGराज्य के लिए किए गए काम की तरह ही, स्टेटसImageViewको 'दिखे' पर सेट करें और कनेक्शन की गड़बड़ी वाले ड्रॉएबल का फिर से इस्तेमाल करें.
MarsApiStatus.ERROR -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.ic_connection_error)
}- 'हो गया' स्थिति के लिए एक केस जोड़ें, जो कि
MarsApiStatus.DONEहै. यहां आपको सही जवाब मिला है. इसलिए, स्टेटसImageViewकी दृश्यता बंद करके इसे छिपाएं.
MarsApiStatus.DONE -> {
statusImageView.visibility = View.GONE
}तीसरा चरण: लेआउट में status ImageView जोड़ना
res/layout/fragment_overview.xmlखोलें.RecyclerViewएलिमेंट के नीचे,ConstraintLayoutके अंदर, यहां दिखाया गयाImageViewजोड़ें.
इसImageViewपर वही पाबंदियां लागू होती हैं जोRecyclerViewपर लागू होती हैं. हालांकि, चौड़ाई और ऊंचाई के लिएwrap_contentका इस्तेमाल किया जाता है, ताकि इमेज को बीच में रखा जा सके. इमेज को स्ट्रेच करके व्यू को भरने के लिए इसका इस्तेमाल नहीं किया जाता.app:marsApiStatusएट्रिब्यूट पर भी ध्यान दें. व्यू मॉडल में स्टेटस प्रॉपर्टी बदलने पर, यह आपकेBindingAdapterको व्यू कॉल करता है.
<ImageView
android:id="@+id/status_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:marsApiStatus="@{viewModel.status}" />- नेटवर्क कनेक्शन न होने की स्थिति को सिम्युलेट करने के लिए, अपने एम्युलेटर या डिवाइस में हवाई जहाज़ मोड चालू करें. ऐप्लिकेशन को कंपाइल और रन करें. देखें कि गड़बड़ी वाली इमेज दिख रही है:

- ऐप्लिकेशन बंद करने के लिए, 'वापस जाएं' बटन पर टैप करें. इसके बाद, हवाई जहाज़ मोड बंद करें. ऐप्लिकेशन को वापस लाने के लिए, हाल ही में इस्तेमाल किए गए ऐप्लिकेशन वाली स्क्रीन का इस्तेमाल करें. आपके नेटवर्क कनेक्शन की स्पीड के हिसाब से, हो सकता है कि इमेज लोड होने से पहले, ऐप्लिकेशन के वेब सेवा से क्वेरी करने पर आपको कुछ समय के लिए लोडिंग स्पिनर दिखे.
Android Studio प्रोजेक्ट: MarsRealEstateGrid
- इमेज को मैनेज करने की प्रोसेस को आसान बनाने के लिए, Glide लाइब्रेरी का इस्तेमाल करें. इससे आपके ऐप्लिकेशन में इमेज डाउनलोड, बफ़र, डिकोड, और कैश मेमोरी में सेव की जा सकती हैं.
- इंटरनेट से इमेज लोड करने के लिए, Glide को दो चीज़ों की ज़रूरत होती है: इमेज का यूआरएल और इमेज को रखने के लिए
ImageViewऑब्जेक्ट. इन विकल्पों को तय करने के लिए, Glide के साथload()औरinto()तरीकों का इस्तेमाल करें. - बाइंडिंग अडैप्टर, एक्सटेंशन के ऐसे तरीके होते हैं जो व्यू और उस व्यू के बाउंड डेटा के बीच में काम करते हैं. बाइंडिंग अडैप्टर, डेटा में बदलाव होने पर कस्टम व्यवहार करते हैं. उदाहरण के लिए, किसी यूआरएल से इमेज को
ImageViewमें लोड करने के लिए Glide को कॉल करना. - बाइंडिंग अडैप्टर, एक्सटेंशन के ऐसे तरीके होते हैं जिन्हें
@BindingAdapterएनोटेशन के साथ एनोटेट किया जाता है. - Glide अनुरोध में विकल्प जोड़ने के लिए,
apply()तरीके का इस्तेमाल करें. उदाहरण के लिए, लोडिंग ड्रॉएबल के बारे में बताने के लिए,placeholder()के साथapply()का इस्तेमाल करें. साथ ही, गड़बड़ी वाले ड्रॉएबल के बारे में बताने के लिए,error()के साथapply()का इस्तेमाल करें. - इमेज की ग्रिड बनाने के लिए,
GridLayoutManagerके साथRecyclerViewका इस्तेमाल करें. - प्रॉपर्टी की सूची में बदलाव होने पर उसे अपडेट करने के लिए,
RecyclerViewऔर लेआउट के बीच बाइंडिंग अडैप्टर का इस्तेमाल करें.
Udacity का कोर्स:
Android डेवलपर का दस्तावेज़:
- ViewModel की खास जानकारी
- LiveData के बारे में खास जानकारी
- कोरूटीन, आधिकारिक दस्तावेज़
- बाइंडिंग अडैप्टर
अन्य:
इस सेक्शन में, उन छात्र-छात्राओं के लिए होमवर्क असाइनमेंट की सूची दी गई है जो किसी शिक्षक के कोर्स के हिस्से के तौर पर इस कोडलैब पर काम कर रहे हैं. शिक्षक के पास ये विकल्प होते हैं:
- अगर ज़रूरी हो, तो होमवर्क असाइन करें.
- छात्र-छात्राओं को बताएं कि होमवर्क असाइनमेंट कैसे सबमिट किए जाते हैं.
- होमवर्क असाइनमेंट को ग्रेड दें.
शिक्षक इन सुझावों का इस्तेमाल अपनी ज़रूरत के हिसाब से कर सकते हैं. साथ ही, वे चाहें, तो कोई दूसरा होमवर्क भी दे सकते हैं.
अगर आपको यह कोडलैब खुद से पूरा करना है, तो अपनी जानकारी की जांच करने के लिए, इन होमवर्क असाइनमेंट का इस्तेमाल करें.
इन सवालों के जवाब दें
पहला सवाल
लोड की गई इमेज को शामिल करने वाले ImageView को दिखाने के लिए, Glide के किस तरीके का इस्तेमाल किया जाता है?
▢ into()
▢ with()
▢ imageview()
▢ apply()
दूसरा सवाल
Glide के लोड होने के दौरान दिखने वाली प्लेसहोल्डर इमेज कैसे तय की जाती है?
▢ ड्रॉ किए जा सकने वाले ऑब्जेक्ट के साथ into() तरीके का इस्तेमाल करें.
▢ RequestOptions() का इस्तेमाल करें और placeholder() तरीके को ड्रॉएबल के साथ कॉल करें.
▢ Glide.placeholder प्रॉपर्टी को किसी ड्रॉएबल को असाइन करें.
▢ RequestOptions() का इस्तेमाल करें और loadingImage() तरीके को ड्रॉएबल के साथ कॉल करें.
तीसरा सवाल
किसी तरीके को बाइंडिंग अडैप्टर के तौर पर कैसे दिखाया जाता है?
▢ LiveData पर setBindingAdapter() वाले तरीके को कॉल करें.
▢ इस तरीके को BindingAdapters.kt नाम की Kotlin फ़ाइल में डालें.
▢ एक्सएमएल लेआउट में android:adapter एट्रिब्यूट का इस्तेमाल करें.
▢ @BindingAdapter का इस्तेमाल करके, तरीके के बारे में एनोटेशन जोड़ें.
अगला सबक शुरू करें:
इस कोर्स में मौजूद अन्य कोडलैब के लिंक के लिए, Android Kotlin Fundamentals कोडलैब का लैंडिंग पेज देखें.