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

ऐप्लिकेशन के इस वर्शन में, प्रॉपर्टी के टाइप (किराया बनाम खरीदना) के साथ काम किया जाता है. साथ ही, बिक्री के लिए उपलब्ध प्रॉपर्टी को मार्क करने के लिए, ग्रिड लेआउट में एक आइकॉन जोड़ा जाता है:

आपने ऐप्लिकेशन के विकल्प मेन्यू में बदलाव किया है, ताकि ग्रिड को फ़िल्टर करके सिर्फ़ किराये या बिक्री के लिए उपलब्ध प्रॉपर्टी दिखाई जा सकें:

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

अब तक, आपने Mars प्रॉपर्टी के डेटा का सिर्फ़ वह हिस्सा इस्तेमाल किया है जो प्रॉपर्टी की इमेज का यूआरएल है. हालांकि, MarsProperty क्लास में तय की गई प्रॉपर्टी के डेटा में आईडी, कीमत, और टाइप (किराया या बिक्री के लिए) भी शामिल होता है. आपको याद दिलाने के लिए, यहां वेब सेवा से मिले JSON डेटा का स्निपेट दिया गया है:
{
"price":8000000,
"id":"424908",
"type":"rent",
"img_src": "http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631290305226E03_DXXX.jpg"
},इस टास्क में, आपको Mars प्रॉपर्टी टाइप का इस्तेमाल करके, बिक्री के लिए उपलब्ध प्रॉपर्टी के खास जानकारी वाले पेज पर डॉलर के निशान वाली इमेज जोड़नी है.
पहला चरण: MarsProperty को अपडेट करके, उसमें टाइप शामिल करना
MarsProperty क्लास, वेब सेवा से मिली हर प्रॉपर्टी के लिए डेटा स्ट्रक्चर तय करती है. पिछले कोडलैब में, आपने Moshi लाइब्रेरी का इस्तेमाल किया था. इससे, मार्स वेब सेवा से मिले रॉ JSON रिस्पॉन्स को अलग-अलग MarsProperty डेटा ऑब्जेक्ट में पार्स किया गया था.
इस चरण में, MarsProperty क्लास में कुछ लॉजिक जोड़ा जाता है. इससे यह पता चलता है कि कोई प्रॉपर्टी किराए पर दी जाती है या नहीं. इसका मतलब है कि टाइप, स्ट्रिंग "rent" या "buy" है या नहीं. इस लॉजिक का इस्तेमाल एक से ज़्यादा जगहों पर किया जाएगा. इसलिए, इसे डेटा क्लास में रखना बेहतर है, न कि इसे दोहराना.
- पिछले कोडलैब से MarsRealEstate ऐप्लिकेशन खोलें. (अगर आपके पास यह ऐप्लिकेशन नहीं है, तो MarsRealEstateGrid डाउनलोड करें.)
network/MarsProperty.ktखोलें.MarsPropertyक्लास डेफ़िनिशन में एक बॉडी जोड़ें. साथ ही,isRentalके लिए एक कस्टम गेटर जोड़ें, जो ऑब्जेक्ट के"rent"टाइप का होने परtrueदिखाता है.
data class MarsProperty(
val id: String,
@Json(name = "img_src") val imgSrcUrl: String,
val type: String,
val price: Double) {
val isRental
get() = type == "rent"
}दूसरा चरण: ग्रिड आइटम का लेआउट अपडेट करना
अब आपको इमेज की ग्रिड के लिए आइटम लेआउट अपडेट करना है, ताकि डॉलर का निशान सिर्फ़ उन प्रॉपर्टी इमेज पर दिखे जो बिक्री के लिए हैं:

डेटा बाइंडिंग एक्सप्रेशन की मदद से, इस टेस्ट को पूरी तरह से ग्रिड आइटम के एक्सएमएल लेआउट में किया जा सकता है.
res/layout/grid_view_item.xmlखोलें. यहRecyclerViewके लिए, ग्रिड लेआउट में मौजूद हर सेल की लेआउट फ़ाइल है. फ़िलहाल, फ़ाइल में प्रॉपर्टी की इमेज के लिए सिर्फ़<ImageView>एलिमेंट मौजूद है.<data>एलिमेंट में,Viewक्लास के लिए<import>एलिमेंट जोड़ें. लेआउट फ़ाइल में डेटा बाइंडिंग एक्सप्रेशन के अंदर किसी क्लास के कॉम्पोनेंट का इस्तेमाल करने के लिए, इंपोर्ट का इस्तेमाल किया जाता है. इस मामले में, आपकोView.GONEऔरView.VISIBLEकॉन्स्टेंट का इस्तेमाल करना है. इसलिए, आपकोViewक्लास को ऐक्सेस करने की ज़रूरत होगी.
<import type="android.view.View"/>- पूरी इमेज व्यू को
FrameLayoutसे घेरें, ताकि डॉलर-साइन ड्रॉएबल को प्रॉपर्टी की इमेज के ऊपर स्टैक किया जा सके.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="170dp">
<ImageView
android:id="@+id/mars_image"
...
</FrameLayout>- नए पैरंट
FrameLayoutको भरने के लिए,ImageViewएट्रिब्यूट के लिएandroid:layout_heightएट्रिब्यूट कोmatch_parentमें बदलें.
android:layout_height="match_parent"FrameLayoutके अंदर, पहले<ImageView>एलिमेंट के ठीक नीचे दूसरा<ImageView>एलिमेंट जोड़ें. यहां दी गई परिभाषा का इस्तेमाल करें. यह इमेज, ग्रिड आइटम के निचले दाएं कोने में, मंगल ग्रह की इमेज के ऊपर दिखती है. साथ ही, डॉलर के निशान वाले आइकॉन के लिए,res/drawable/ic_for_sale_outline.xmlमें तय किए गए ड्रॉएबल का इस्तेमाल करती है.
<ImageView
android:id="@+id/mars_property_type"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_gravity="bottom|end"
android:adjustViewBounds="true"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_for_sale_outline"
tools:src="@drawable/ic_for_sale_outline"/>mars_property_typeइमेज व्यू मेंandroid:visibilityएट्रिब्यूट जोड़ें. प्रॉपर्टी टाइप की जांच करने के लिए, बाइंडिंग एक्सप्रेशन का इस्तेमाल करें. साथ ही, किराये पर लेने के लिएView.GONEया खरीदने के लिएView.VISIBLEके तौर पर दृश्यता असाइन करें.
android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"अब तक आपने सिर्फ़ उन लेआउट में बाइंडिंग एक्सप्रेशन देखे हैं जिनमें <data> एलिमेंट में तय किए गए अलग-अलग वैरिएबल का इस्तेमाल किया जाता है. बाइंडिंग एक्सप्रेशन बहुत असरदार होते हैं. इनकी मदद से, टेस्ट और गणित के हिसाब-किताब जैसे काम, पूरी तरह से अपने एक्सएमएल लेआउट में किए जा सकते हैं. इस मामले में, टेस्ट करने के लिए टर्नरी ऑपरेटर (?:) का इस्तेमाल किया जाता है. जैसे, क्या यह ऑब्जेक्ट किराये पर दिया जाता है? 'सही' के लिए एक नतीजा (View.GONE के साथ डॉलर-साइन आइकॉन छिपाएं) और 'गलत' के लिए दूसरा नतीजा (View.VISIBLE के साथ वह आइकॉन दिखाएं) दिया जाता है.
नई पूरी grid_view_item.xml फ़ाइल यहां दी गई है:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View"/>
<variable
name="property"
type="com.example.android.marsrealestate.network.MarsProperty" />
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="170dp">
<ImageView
android:id="@+id/mars_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
android:padding="2dp"
app:imageUrl="@{property.imgSrcUrl}"
tools:src="@tools:sample/backgrounds/scenic"/>
<ImageView
android:id="@+id/mars_property_type"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_gravity="bottom|end"
android:adjustViewBounds="true"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_for_sale_outline"
android:visibility="@{property.rental ? View.GONE : View.VISIBLE}"
tools:src="@drawable/ic_for_sale_outline"/>
</FrameLayout>
</layout>- ऐप्लिकेशन को कंपाइल और रन करें. ध्यान दें कि किराए पर न दिए जाने वाले प्रॉडक्ट के लिए, डॉलर के निशान वाला आइकॉन मौजूद है.

फ़िलहाल, आपका ऐप्लिकेशन खास जानकारी वाली ग्रिड में Mars की सभी प्रॉपर्टी दिखाता है. अगर कोई व्यक्ति मंगल ग्रह पर किराये की प्रॉपर्टी खोज रहा है, तो उसे यह बताने वाले आइकॉन दिखेंगे कि कौनसी प्रॉपर्टी बिक्री के लिए उपलब्ध हैं. हालांकि, पेज पर अब भी स्क्रोल करने के लिए कई प्रॉपर्टी मौजूद हैं. इस टास्क में, आपको खास जानकारी वाले फ़्रैगमेंट में एक विकल्प मेन्यू जोड़ना है. इससे उपयोगकर्ता, सिर्फ़ किराए पर उपलब्ध प्रॉपर्टी, सिर्फ़ बिक्री के लिए उपलब्ध प्रॉपर्टी या सभी प्रॉपर्टी दिखा पाएगा.

इस टास्क को पूरा करने का एक तरीका यह है कि खास जानकारी वाली ग्रिड में मौजूद हर MarsProperty के टाइप की जांच करें और सिर्फ़ मैच करने वाली प्रॉपर्टी दिखाएं. हालांकि, Mars की वेब सेवा में एक क्वेरी पैरामीटर या विकल्प (filter) होता है. इसकी मदद से, सिर्फ़ rent या buy टाइप की प्रॉपर्टी पाई जा सकती हैं. इस फ़िल्टर क्वेरी का इस्तेमाल, ब्राउज़र में realestate वेब सेवा के यूआरएल के साथ इस तरह किया जा सकता है:
https://android-kotlin-fun-mars-server.appspot.com/realestate?filter=buyइस टास्क में, आपको MarsApiService क्लास में बदलाव करना है, ताकि Retrofit की मदद से वेब सेवा के अनुरोध में क्वेरी का विकल्प जोड़ा जा सके. इसके बाद, उस क्वेरी के विकल्प का इस्तेमाल करके, Mars प्रॉपर्टी का पूरा डेटा फिर से डाउनलोड करने के लिए, विकल्प मेन्यू को हुक अप करें. वेब सेवा से मिलने वाले जवाब में सिर्फ़ वे प्रॉपर्टी शामिल होती हैं जिनमें आपकी दिलचस्पी है. इसलिए, आपको खास जानकारी वाली ग्रिड के लिए व्यू डिसप्ले लॉजिक में कोई बदलाव करने की ज़रूरत नहीं है.
पहला चरण: Mars API सेवा को अपडेट करना
अनुरोध बदलने के लिए, आपको उस MarsApiService क्लास पर फिर से जाना होगा जिसे आपने इस सीरीज़ के पहले कोडलैब में लागू किया था. फ़िल्टर करने वाले एपीआई को उपलब्ध कराने के लिए, क्लास में बदलाव करें.
network/MarsApiService.ktखोलें. इंपोर्ट के ठीक नीचे,enumनाम काMarsApiFilterबनाएं. इससे उन कॉन्स्टेंट को तय किया जा सकेगा जो वेब सेवा की क्वेरी वैल्यू से मेल खाते हैं.
enum class MarsApiFilter(val value: String) {
SHOW_RENT("rent"),
SHOW_BUY("buy"),
SHOW_ALL("all") }- फ़िल्टर क्वेरी के लिए स्ट्रिंग इनपुट लेने के लिए,
getProperties()तरीके में बदलाव करें. साथ ही, उस इनपुट को@Query("filter")के साथ एनोटेट करें. जैसा कि यहां दिखाया गया है.
जब कहा जाए, तबretrofit2.http.Queryइंपोर्ट करें.@Queryएनोटेशन,getProperties()तरीके (और इस तरह Retrofit) को फ़िल्टर करने के विकल्प के साथ वेब सेवा का अनुरोध करने के लिए कहता है. हर बारgetProperties()को कॉल करने पर, अनुरोध किए गए यूआरएल में?filter=typeवाला हिस्सा शामिल होता है. इससे वेब सेवा को उस क्वेरी से मिलते-जुलते नतीजे दिखाने का निर्देश मिलता है.
fun getProperties(@Query("filter") type: String): दूसरा चरण: खास जानकारी वाले व्यू मॉडल को अपडेट करना
आपने OverviewViewModel में getMarsRealEstateProperties() तरीके का इस्तेमाल करके, MarsApiService से डेटा का अनुरोध किया है. अब आपको उस अनुरोध को अपडेट करना होगा, ताकि वह फ़िल्टर आर्ग्युमेंट ले सके.
overview/OverviewViewModel.ktखोलें. पिछले चरण में किए गए बदलावों की वजह से, आपको Android Studio में गड़बड़ियां दिखेंगी.getMarsRealEstateProperties()कॉल में,MarsApiFilter(फ़िल्टर की संभावित वैल्यू का enum) को पैरामीटर के तौर पर जोड़ें.
अनुरोध किए जाने परcom.example.android.marsrealestate.network.MarsApiFilterइंपोर्ट करें.
private fun getMarsRealEstateProperties(filter: MarsApiFilter) {- Retrofit सेवा में
getProperties()को किए गए कॉल में बदलाव करें, ताकि उस फ़िल्टर क्वेरी को स्ट्रिंग के तौर पर पास किया जा सके.
var getPropertiesDeferred = MarsApi.retrofitService.getProperties(filter.value)init {}ब्लॉक में,getMarsRealEstateProperties()को आर्ग्युमेंट के तौर परMarsApiFilter.SHOW_ALLपास करें, ताकि ऐप्लिकेशन के पहली बार लोड होने पर सभी प्रॉपर्टी दिखें.
init {
getMarsRealEstateProperties(MarsApiFilter.SHOW_ALL)
}- क्लास के आखिर में, एक
updateFilter()मैथड जोड़ें. यहMarsApiFilterआर्ग्युमेंट लेता है और उस आर्ग्युमेंट के साथgetMarsRealEstateProperties()को कॉल करता है.
fun updateFilter(filter: MarsApiFilter) {
getMarsRealEstateProperties(filter)
}तीसरा चरण: फ़्रैगमेंट को विकल्प मेन्यू से कनेक्ट करना
आखिरी चरण में, ओवरफ़्लो मेन्यू को फ़्रैगमेंट से जोड़ना होता है. इससे जब उपयोगकर्ता कोई मेन्यू विकल्प चुनता है, तब व्यू मॉडल पर updateFilter() कॉल किया जा सकता है.
res/menu/overflow_menu.xmlखोलें. MarsRealEstate ऐप्लिकेशन में पहले से ही एक ओवरफ़्लो मेन्यू मौजूद है. इसमें तीन विकल्प उपलब्ध हैं: सभी प्रॉपर्टी दिखाना, सिर्फ़ किराए पर उपलब्ध प्रॉपर्टी दिखाना, और सिर्फ़ बिक्री के लिए उपलब्ध प्रॉपर्टी दिखाना.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/show_all_menu"
android:title="@string/show_all" />
<item
android:id="@+id/show_rent_menu"
android:title="@string/show_rent" />
<item
android:id="@+id/show_buy_menu"
android:title="@string/show_buy" />
</menu>overview/OverviewFragment.ktखोलें. क्लास के आखिर में, मेन्यू आइटम चुनने के लिएonOptionsItemSelected()तरीके का इस्तेमाल करें.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
} onOptionsItemSelected()में, सही फ़िल्टर के साथ व्यू मॉडल परupdateFilter()वाले तरीके को कॉल करें. विकल्पों के बीच स्विच करने के लिए, Kotlinwhen {}ब्लॉक का इस्तेमाल करें. डिफ़ॉल्ट फ़िल्टर वैल्यू के लिए,MarsApiFilter.SHOW_ALLका इस्तेमाल करें.trueको वापस लाओ, क्योंकि तुमने मेन्यू आइटम को हैंडल कर लिया है. अनुरोध किए जाने पर,MarsApiFilter(com.example.android.marsrealestate.network.MarsApiFilter) को इंपोर्ट करें.onOptionsItemSelected()का पूरा तरीका यहां दिया गया है.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
viewModel.updateFilter(
when (item.itemId) {
R.id.show_rent_menu -> MarsApiFilter.SHOW_RENT
R.id.show_buy_menu -> MarsApiFilter.SHOW_BUY
else -> MarsApiFilter.SHOW_ALL
}
)
return true
}- ऐप्लिकेशन को कंपाइल और रन करें. ऐप्लिकेशन, प्रॉपर्टी के सभी टाइप के साथ पहली खास जानकारी वाली ग्रिड लॉन्च करता है. साथ ही, बिक्री के लिए उपलब्ध प्रॉपर्टी को डॉलर के निशान से मार्क करता है.
- विकल्प मेन्यू से, किराया चुनें. प्रॉपर्टी फिर से लोड होती हैं और उनमें से किसी के भी साथ डॉलर का आइकॉन नहीं दिखता. (सिर्फ़ किराये पर दी जाने वाली प्रॉपर्टी दिखाई जाती हैं.) फ़िल्टर की गई प्रॉपर्टी दिखाने के लिए, डिसप्ले को रीफ़्रेश होने में कुछ समय लग सकता है.
- विकल्प मेन्यू से खरीदें चुनें. प्रॉपर्टी फिर से लोड होती हैं और सभी डॉलर के आइकॉन के साथ दिखती हैं. (सिर्फ़ बिक्री के लिए उपलब्ध प्रॉपर्टी दिखाई जाती हैं.)
अब आपके पास Mars की प्रॉपर्टी के आइकॉन की स्क्रोल करने वाली ग्रिड है. हालांकि, अब आपको ज़्यादा जानकारी चाहिए. इस टास्क में, किसी प्रॉपर्टी की जानकारी दिखाने के लिए, एक जानकारी वाला फ़्रैगमेंट जोड़ा जाता है. ज़्यादा जानकारी वाले फ़्रैगमेंट में, बड़ी इमेज, कीमत, और प्रॉपर्टी का टाइप दिखेगा. इससे पता चलेगा कि प्रॉपर्टी किराये पर उपलब्ध है या बिक्री के लिए.

जब उपयोगकर्ता खास जानकारी वाली ग्रिड में मौजूद किसी इमेज पर टैप करता है, तब यह फ़्रैगमेंट लॉन्च होता है. इसके लिए, आपको onClick ग्रिड आइटम में onClick लिसनर जोड़ना होगा. इसके बाद, नए फ़्रैगमेंट पर जाएं.RecyclerView इन सभी सबक में, आपने ViewModel में LiveData बदलाव करके नेविगेट किया है. आपने नेविगेशन कॉम्पोनेंट के Safe Args प्लगिन का इस्तेमाल करके, चुनी गई MarsProperty जानकारी को खास जानकारी वाले फ़्रैगमेंट से ज़्यादा जानकारी वाले फ़्रैगमेंट में पास किया है.
पहला चरण: जानकारी वाले व्यू का मॉडल बनाएं और जानकारी वाले लेआउट को अपडेट करें
आपने खास जानकारी वाले व्यू मॉडल और फ़्रैगमेंट के लिए जिस प्रोसेस का इस्तेमाल किया था, अब आपको उसी प्रोसेस का इस्तेमाल करके, ज़्यादा जानकारी वाले फ़्रैगमेंट के लिए व्यू मॉडल और लेआउट फ़ाइलें लागू करनी होंगी.
detail/DetailViewModel.ktखोलें. नेटवर्क से जुड़ी Kotlin फ़ाइलेंnetworkफ़ोल्डर में और खास जानकारी वाली फ़ाइलेंoverviewमें होती हैं. इसी तरह,detailफ़ोल्डर में, ज़्यादा जानकारी वाले व्यू से जुड़ी फ़ाइलें होती हैं. ध्यान दें किDetailViewModelक्लास (फ़िलहाल खाली है) कंस्ट्रक्टर मेंmarsPropertyको पैरामीटर के तौर पर लेता है.
class DetailViewModel( marsProperty: MarsProperty,
app: Application) : AndroidViewModel(app) {
}- क्लास की परिभाषा में, चुनी गई Mars प्रॉपर्टी के लिए
LiveDataजोड़ें, ताकि वह जानकारी ज़्यादा जानकारी वाले व्यू में दिख सके.MarsPropertyको होल्ड करने के लिए,MutableLiveDataबनाने के सामान्य पैटर्न का पालन करें. इसके बाद, न बदलने वाली सार्वजनिकLiveDataप्रॉपर्टी को दिखाएं.
अनुरोध किए जाने पर,androidx.lifecycle.LiveDataऔरandroidx.lifecycle.MutableLiveDataइंपोर्ट करें.
private val _selectedProperty = MutableLiveData<MarsProperty>()
val selectedProperty: LiveData<MarsProperty>
get() = _selectedProperty- एक
init {}ब्लॉक बनाएं और कंस्ट्रक्टर से मिलेMarsPropertyऑब्जेक्ट की मदद से, चुनी गई Mars प्रॉपर्टी की वैल्यू सेट करें.
init {
_selectedProperty.value = marsProperty
}res/layout/fragment_detail.xmlखोलें और उसे डिज़ाइन व्यू में देखें.
यह जानकारी वाले फ़्रैगमेंट के लिए लेआउट फ़ाइल है. इसमें बड़ी फ़ोटो के लिएImageView, प्रॉपर्टी टाइप (किराये पर या बिक्री के लिए) के लिएTextView, और कीमत के लिएTextViewशामिल है. ध्यान दें कि कंस्ट्रेंट लेआउट कोScrollViewके साथ रैप किया गया है. इसलिए, अगर व्यू डिसप्ले के लिए बहुत बड़ा हो जाता है, तो यह अपने-आप स्क्रोल हो जाएगा. उदाहरण के लिए, जब उपयोगकर्ता इसे लैंडस्केप मोड में देखता है.- लेआउट के टेक्स्ट टैब पर जाएं. लेआउट में सबसे ऊपर,
<ScrollView>एलिमेंट से ठीक पहले,<data>एलिमेंट जोड़ें, ताकि ज़्यादा जानकारी वाले व्यू मॉडल को लेआउट से जोड़ा जा सके.
<data>
<variable
name="viewModel"
type="com.example.android.marsrealestate.detail.DetailViewModel" />
</data>app:imageUrlएट्रिब्यूट कोImageViewएलिमेंट में जोड़ें. इसे व्यू मॉडल की चुनी गई प्रॉपर्टी सेimgSrcUrlपर सेट करें.
Glide का इस्तेमाल करके इमेज लोड करने वाला बाइंडिंग अडैप्टर, यहां भी अपने-आप इस्तेमाल हो जाएगा. ऐसा इसलिए, क्योंकि यह अडैप्टर सभीapp:imageUrlएट्रिब्यूट पर नज़र रखता है.
app:imageUrl="@{viewModel.selectedProperty.imgSrcUrl}"दूसरा चरण: ओवरव्यू व्यू मॉडल में नेविगेशन तय करना
जब उपयोगकर्ता खास जानकारी वाले मॉडल में किसी फ़ोटो पर टैप करता है, तो उसे उस फ़्रैगमेंट पर रीडायरेक्ट किया जाना चाहिए जिसमें क्लिक किए गए आइटम के बारे में जानकारी दी गई हो.
overview/OverviewViewModel.ktखोलें._navigateToSelectedPropertyMutableLiveDataप्रॉपर्टी जोड़ें और उसे न बदलने वालेLiveDataके साथ दिखाएं.
जब यहLiveDataबदलकर गैर-शून्य हो जाता है, तब नेविगेशन ट्रिगर होता है. (जल्द ही, इस वैरिएबल को मॉनिटर करने और नेविगेशन को ट्रिगर करने के लिए कोड जोड़ा जाएगा.)
private val _navigateToSelectedProperty = MutableLiveData<MarsProperty>()
val navigateToSelectedProperty: LiveData<MarsProperty>
get() = _navigateToSelectedProperty- क्लास के आखिर में, एक
displayPropertyDetails()तरीका जोड़ें. यह तरीका, _navigateToSelectedPropertyको चुनी गई Mars प्रॉपर्टी पर सेट करता है.
fun displayPropertyDetails(marsProperty: MarsProperty) {
_navigateToSelectedProperty.value = marsProperty
}displayPropertyDetailsComplete()तरीका जोड़ें, जो_navigateToSelectedPropertyकी वैल्यू को शून्य कर देता है. नेविगेशन की स्थिति को 'पूरा हुआ' के तौर पर मार्क करने के लिए, आपको इसकी ज़रूरत होगी. साथ ही, इससे यह पक्का किया जा सकेगा कि उपयोगकर्ता के जानकारी वाले पेज से वापस आने पर, नेविगेशन फिर से ट्रिगर न हो.
fun displayPropertyDetailsComplete() {
_navigateToSelectedProperty.value = null
}तीसरा चरण: ग्रिड अडैप्टर और फ़्रैगमेंट में क्लिक लिसनर सेट अप करना
overview/PhotoGridAdapter.ktखोलें. क्लास के आखिर में, एक कस्टमOnClickListenerक्लास बनाएं. यह क्लास,marsPropertyपैरामीटर के साथ लैम्डा लेती है. क्लास में,onClick()फ़ंक्शन को lambda पैरामीटर पर सेट करें.
class OnClickListener(val clickListener: (marsProperty:MarsProperty) -> Unit) {
fun onClick(marsProperty:MarsProperty) = clickListener(marsProperty)
}- ऊपर की ओर स्क्रोल करके,
PhotoGridAdapterके लिए क्लास डेफ़िनिशन पर जाएं. इसके बाद, कंस्ट्रक्टर में एक प्राइवेटOnClickListenerप्रॉपर्टी जोड़ें.
class PhotoGridAdapter( private val onClickListener: OnClickListener ) :
ListAdapter<MarsProperty,
PhotoGridAdapter.MarsPropertyViewHolder>(DiffCallback) {onBindviewHolder()तरीके में, ग्रिड आइटम मेंonClickListenerजोड़कर फ़ोटो को क्लिक करने लायक बनाएं.getItem() and bind()को कॉल करने के बीच में, क्लिक लिसनर को तय करें.
override fun onBindViewHolder(holder: MarsPropertyViewHolder, position: Int) {
val marsProperty = getItem(position)
holder.itemView.setOnClickListener {
onClickListener.onClick(marsProperty)
}
holder.bind(marsProperty)
}overview/OverviewFragment.ktखोलें.onCreateView()तरीके में,binding.photosGrid.adapterप्रॉपर्टी को शुरू करने वाली लाइन को यहां दिखाई गई लाइन से बदलें.
यह कोड,PhotoGridAdapter.onClickListenerऑब्जेक्ट कोPhotoGridAdapterकंस्ट्रक्टर में जोड़ता है. साथ ही, पास किए गएMarsPropertyऑब्जेक्ट के साथviewModel.displayPropertyDetails()को कॉल करता है. इससे नेविगेशन के लिए व्यू मॉडल मेंLiveDataट्रिगर होता है.
binding.photosGrid.adapter = PhotoGridAdapter(PhotoGridAdapter.OnClickListener {
viewModel.displayPropertyDetails(it)
})चौथा चरण: नेविगेशन ग्राफ़ में बदलाव करना और MarsProperty को पार्सल करने लायक बनाना
जब कोई उपयोगकर्ता खास जानकारी वाली ग्रिड में मौजूद किसी फ़ोटो पर टैप करता है, तो ऐप्लिकेशन को ज़्यादा जानकारी वाले फ़्रैगमेंट पर जाना चाहिए. साथ ही, उसे चुनी गई मंगल ग्रह की प्रॉपर्टी की जानकारी देनी चाहिए, ताकि ज़्यादा जानकारी वाले व्यू में वह जानकारी दिख सके.

फ़िलहाल, आपके पास टैप को हैंडल करने के लिए PhotoGridAdapter से क्लिक लिसनर है. साथ ही, व्यू मॉडल से नेविगेशन को ट्रिगर करने का तरीका है. हालांकि, आपके पास अब तक ऐसा कोई MarsProperty ऑब्जेक्ट नहीं है जिसे ज़्यादा जानकारी वाले फ़्रैगमेंट में पास किया जा रहा हो. इसके लिए, नेविगेशन कॉम्पोनेंट से Safe Args का इस्तेमाल किया जाता है.
res/navigation/nav_graph.xmlखोलें. नेविगेशन ग्राफ़ के लिए एक्सएमएल कोड देखने के लिए, टेक्स्ट टैब पर क्लिक करें.- ज़्यादा जानकारी वाले फ़्रैगमेंट के लिए,
<fragment>एलिमेंट में नीचे दिखाया गया<argument>एलिमेंट जोड़ें. इस आर्ग्युमेंट कोselectedPropertyकहा जाता है और इसका टाइपMarsPropertyहै.
<argument
android:name="selectedProperty"
app:argType="com.example.android.marsrealestate.network.MarsProperty"
/>- ऐप्लिकेशन को कंपाइल करें. नेविगेशन में गड़बड़ी दिख रही है, क्योंकि
MarsPropertyपार्सल करने लायक नहीं है.Parcelableइंटरफ़ेस की मदद से ऑब्जेक्ट को क्रम से लगाया जा सकता है, ताकि ऑब्जेक्ट का डेटा फ़्रैगमेंट या ऐक्टिविटी के बीच पास किया जा सके. इस मामले में,MarsPropertyऑब्जेक्ट में मौजूद डेटा को Safe Args के ज़रिए, जानकारी वाले फ़्रैगमेंट में पास करने के लिए,MarsPropertyकोParcelableइंटरफ़ेस लागू करना होगा. अच्छी बात यह है कि Kotlin, उस इंटरफ़ेस को लागू करने के लिए एक आसान शॉर्टकट उपलब्ध कराता है. network/MarsProperty.ktखोलें. क्लास डेफ़िनिशन में@Parcelizeएनोटेशन जोड़ें.
जब अनुरोध किया जाए, तबkotlinx.android.parcel.Parcelizeइंपोर्ट करें.@Parcelizeएनोटेशन, Kotlin Android एक्सटेंशन का इस्तेमाल करता है. इससे इस क्लास के लिए,Parcelableइंटरफ़ेस में मौजूद तरीकों को अपने-आप लागू किया जा सकता है. आपको कुछ और करने की ज़रूरत नहीं है!
@Parcelize
data class MarsProperty (Parcelableको बढ़ाने के लिए,MarsPropertyकी क्लास की परिभाषा बदलें.
अनुरोध किए जाने पर,android.os.Parcelableइंपोर्ट करें.MarsPropertyक्लास की परिभाषा अब ऐसी दिखती है:
@Parcelize
data class MarsProperty (
val id: String,
@Json(name = "img_src") val imgSrcUrl: String,
val type: String,
val price: Double) : Parcelable {पांचवां चरण: फ़्रैगमेंट कनेक्ट करना
अब भी नेविगेट नहीं किया जा रहा है. असल नेविगेशन, फ़्रैगमेंट में होता है. इस चरण में, आपको खास जानकारी और ज़्यादा जानकारी वाले फ़्रैगमेंट के बीच नेविगेशन लागू करने के लिए, आखिरी बिट जोड़नी होती हैं.
overview/OverviewFragment.ktखोलें.onCreateView()में, फ़ोटो ग्रिड अडैप्टर को शुरू करने वाली लाइनों के नीचे, यहां दिखाई गई लाइनों को जोड़ें. इससे, ओवरव्यू व्यू मॉडल सेnavigatedToSelectedPropertyको देखा जा सकेगा.
अनुरोध किए जाने पर,androidx.lifecycle.Observerऔरandroidx.navigation.fragment.findNavControllerइंपोर्ट करें.
ऑब्ज़र्वर यह जांच करता है कि क्याMarsProperty—लैंबडा में मौजूदit—शून्य नहीं है. अगर ऐसा है, तो उसेfindNavController()वाले फ़्रैगमेंट से नेविगेशन कंट्रोलर मिलता है.displayPropertyDetailsComplete()को कॉल करें, ताकि व्यू मॉडल कोLiveDataको शून्य स्थिति पर रीसेट करने के लिए कहा जा सके. इससे, ऐप्लिकेशन केOverviewFragmentपर वापस आने पर, नेविगेशन को गलती से फिर से ट्रिगर नहीं किया जाएगा.
viewModel.navigateToSelectedProperty.observe(this, Observer {
if ( null != it ) {
this.findNavController().navigate(
OverviewFragmentDirections.actionShowDetail(it))
viewModel.displayPropertyDetailsComplete()
}
})detail/DetailFragment.ktखोलें. इस लाइन कोonCreateView()तरीके में,setLifecycleOwner()को कॉल करने के ठीक नीचे जोड़ें. इस लाइन से, Safe Args से चुना गयाMarsPropertyऑब्जेक्ट मिलता है.
ध्यान दें कि इसमें Kotlin के not-null assertion ऑपरेटर (!!) का इस्तेमाल किया गया है. अगरselectedPropertyमौजूद नहीं है, तो कोई गड़बड़ी हुई है. ऐसे में, आपको कोड से null pointer चाहिए. (प्रोडक्शन कोड में, आपको उस गड़बड़ी को किसी तरह से ठीक करना चाहिए.)
val marsProperty = DetailFragmentArgs.fromBundle(arguments!!).selectedProperty- नया
DetailViewModelFactoryपाने के लिए, यह लाइन जोड़ें.DetailViewModelका इंस्टेंस पाने के लिए,DetailViewModelFactoryका इस्तेमाल करें. स्टार्टर ऐप्लिकेशन मेंDetailViewModelFactoryको लागू किया गया है. इसलिए, आपको सिर्फ़ इसे शुरू करना है.
val viewModelFactory = DetailViewModelFactory(marsProperty, application)- आखिर में, इस लाइन को जोड़ें, ताकि आपको फ़ैक्ट्री से
DetailViewModelमिल सके और सभी हिस्सों को कनेक्ट किया जा सके.
binding.viewModel = ViewModelProviders.of(
this, viewModelFactory).get(DetailViewModel::class.java)- ऐप्लिकेशन को कंपाइल और रन करें. इसके बाद, मंगल ग्रह की किसी भी प्रॉपर्टी की फ़ोटो पर टैप करें. इसके बाद, उस प्रॉपर्टी की जानकारी के लिए ज़्यादा जानकारी वाला फ़्रैगमेंट दिखेगा. खास जानकारी वाले पेज पर वापस जाने के लिए, 'वापस जाएं' बटन पर टैप करें. ध्यान दें कि ज़्यादा जानकारी वाली स्क्रीन में अब भी कुछ ही जानकारी दिख रही है. अगले टास्क में, आपको उस जानकारी वाले पेज में प्रॉपर्टी का डेटा जोड़ना होगा.
फ़िलहाल, ज़्यादा जानकारी वाले पेज पर सिर्फ़ मंगल ग्रह की वही फ़ोटो दिखती है जो आपको खास जानकारी वाले पेज पर दिखती है. MarsProperty क्लास में प्रॉपर्टी का टाइप (किराये पर लेना या खरीदना) और प्रॉपर्टी की कीमत भी होती है. जानकारी वाले पेज पर, ये दोनों वैल्यू शामिल होनी चाहिए. साथ ही, यह भी बताया जाना चाहिए कि किराये की प्रॉपर्टी के लिए, कीमत हर महीने के हिसाब से है. इन दोनों को लागू करने के लिए, व्यू मॉडल में LiveData ट्रांसफ़ॉर्मेशन का इस्तेमाल करें.
res/values/strings.xmlखोलें. स्टार्टर कोड में स्ट्रिंग रिसॉर्स शामिल होते हैं. ये स्ट्रिंग रिसॉर्स, नीचे दिखाए गए हैं. इनकी मदद से, ज़्यादा जानकारी वाले व्यू के लिए स्ट्रिंग बनाई जा सकती हैं. कीमत के लिए, प्रॉपर्टी के टाइप के हिसाब सेdisplay_price_monthly_rentalयाdisplay_priceसंसाधन का इस्तेमाल किया जाएगा.
<string name="type_rent">Rent</string>
<string name="type_sale">Sale</string>
<string name="display_type">For %s</string>
<string name="display_price_monthly_rental">$%,.0f/month</string>
<string name="display_price">$%,.0f</string>detail/DetailViewModel.ktखोलें. क्लास के सबसे नीचे, यहां दिया गया कोड जोड़ें.
अनुरोध किए जाने पर,androidx.lifecycle.Transformationsइंपोर्ट करें.
इस ट्रांसफ़ॉर्मेशन से यह पता चलता है कि चुनी गई प्रॉपर्टी किराये पर दी जाती है या नहीं. इसके लिए, पहले टास्क में इस्तेमाल किए गए टेस्ट का ही इस्तेमाल किया जाता है. अगर प्रॉपर्टी किराए पर दी जाती है, तो ट्रांसफ़ॉर्मेशन, Kotlinwhen {}स्विच वाले संसाधनों से सही स्ट्रिंग चुनता है. इन दोनों स्ट्रिंग के आखिर में एक नंबर होना चाहिए. इसलिए, बाद मेंproperty.priceको जोड़ें.
val displayPropertyPrice = Transformations.map(selectedProperty) {
app.applicationContext.getString(
when (it.isRental) {
true -> R.string.display_price_monthly_rental
false -> R.string.display_price
}, it.price)
}- प्रोजेक्ट में स्ट्रिंग संसाधनों का ऐक्सेस पाने के लिए, जनरेट की गई
Rक्लास को इंपोर्ट करें.
import com.example.android.marsrealestate.RdisplayPropertyPriceट्रांसफ़ॉर्मेशन के बाद, नीचे दिखाया गया कोड जोड़ें. यह ट्रांसफ़ॉर्मेशन, कई स्ट्रिंग रिसॉर्स को एक साथ जोड़ता है. यह इस बात पर निर्भर करता है कि प्रॉपर्टी का टाइप किराये पर उपलब्ध जगह है या नहीं.
val displayPropertyType = Transformations.map(selectedProperty) {
app.applicationContext.getString(R.string.display_type,
app.applicationContext.getString(
when (it.isRental) {
true -> R.string.type_rent
false -> R.string.type_sale
}))
}res/layout/fragment_detail.xmlखोलें. आपको बस एक और काम करना है. आपको नई स्ट्रिंग (जिन्हें आपनेLiveDataट्रांसफ़ॉर्मेशन की मदद से बनाया है) को ज़्यादा जानकारी वाले व्यू से बाइंड करना होगा. इसके लिए, प्रॉपर्टी टाइप टेक्स्ट के लिए टेक्स्ट फ़ील्ड की वैल्यू कोviewModel.displayPropertyTypeपर सेट करें. साथ ही, कीमत की वैल्यू के टेक्स्ट के लिए टेक्स्ट फ़ील्ड की वैल्यू कोviewModel.displayPropertyPriceपर सेट करें.
<TextView
android:id="@+id/property_type_text"
...
android:text="@{viewModel.displayPropertyType}"
...
tools:text="To Rent" />
<TextView
android:id="@+id/price_value_text"
...
android:text="@{viewModel.displayPropertyPrice}"
...
tools:text="$100,000" />- ऐप्लिकेशन को कंपाइल और चलाएं. अब प्रॉपर्टी का सारा डेटा, जानकारी वाले पेज पर अच्छी तरह से फ़ॉर्मैट किया हुआ दिखेगा.

Android Studio प्रोजेक्ट: MarsRealEstateFinal
बाइंडिंग एक्सप्रेशन
- एक्सएमएल लेआउट फ़ाइलों में बाइंडिंग एक्सप्रेशन का इस्तेमाल करके, बाइंड किए गए डेटा पर प्रोग्राम से जुड़ी सामान्य कार्रवाइयां की जा सकती हैं. जैसे, गणित के हिसाब-किताब या शर्त के हिसाब से जांच करना.
- अपनी लेआउट फ़ाइल में क्लास का रेफ़रंस देने के लिए,
<data>टैग के अंदर<import>टैग का इस्तेमाल करें.
वेब सेवा की क्वेरी के विकल्प
- वेब सेवाओं के अनुरोधों में वैकल्पिक पैरामीटर शामिल किए जा सकते हैं.
- अनुरोध में क्वेरी पैरामीटर तय करने के लिए, Retrofit में
@Queryएनोटेशन का इस्तेमाल करें.
Udacity का कोर्स:
Android डेवलपर का दस्तावेज़:
- ViewModel की खास जानकारी
- LiveData के बारे में खास जानकारी
- बाइंडिंग अडैप्टर
- लेआउट और बाइंडिंग एक्सप्रेशन
- नेविगेशन
- नेविगेशन कॉम्पोनेंट का इस्तेमाल शुरू करना
- डेटा को एक डेस्टिनेशन से दूसरे डेस्टिनेशन पर भेजना (इसमें Safe Args के बारे में भी बताया गया है)
Transformationsक्लासViewModelProviderक्लासViewModelProvider.Factoryक्लास
अन्य:
इस सेक्शन में, उन छात्र-छात्राओं के लिए होमवर्क असाइनमेंट की सूची दी गई है जो किसी शिक्षक के कोर्स के हिस्से के तौर पर इस कोडलैब पर काम कर रहे हैं. शिक्षक के पास ये विकल्प होते हैं:
- अगर ज़रूरी हो, तो होमवर्क असाइन करें.
- छात्र-छात्राओं को बताएं कि होमवर्क असाइनमेंट कैसे सबमिट किए जाते हैं.
- होमवर्क असाइनमेंट को ग्रेड दें.
शिक्षक इन सुझावों का इस्तेमाल अपनी ज़रूरत के हिसाब से कर सकते हैं. साथ ही, वे चाहें, तो कोई दूसरा होमवर्क भी दे सकते हैं.
अगर आपको यह कोडलैब खुद से पूरा करना है, तो अपनी जानकारी की जांच करने के लिए, इन होमवर्क असाइनमेंट का इस्तेमाल करें.
इन सवालों के जवाब दें
पहला सवाल
एक्सएमएल लेआउट फ़ाइल में <import> टैग क्या करता है?
▢ एक लेआउट फ़ाइल को दूसरी फ़ाइल में शामिल करें.
▢ लेआउट फ़ाइल में Kotlin कोड एम्बेड करें.
▢ डेटा से जुड़ी प्रॉपर्टी का ऐक्सेस दें.
▢ इससे आपको बाइंडिंग एक्सप्रेशन में क्लास और क्लास के सदस्यों का रेफ़रंस देने की सुविधा मिलती है.
दूसरा सवाल
Retrofit में, REST वेब सर्विस कॉल में क्वेरी का विकल्प कैसे जोड़ा जाता है?
▢ क्वेरी को अनुरोध यूआरएल के आखिर में जोड़ें.
▢ क्वेरी के लिए, अनुरोध करने वाले फ़ंक्शन में एक पैरामीटर जोड़ें और उस पैरामीटर को @Query से एनोटेट करें.
▢ अनुरोध बनाने के लिए, Query क्लास का इस्तेमाल करें.
▢ Retrofit बिल्डर में addQuery() तरीके का इस्तेमाल करें.
अगला लेसन शुरू करें:
इस कोर्स में मौजूद अन्य कोडलैब के लिंक के लिए, Android Kotlin Fundamentals कोडलैब का लैंडिंग पेज देखें.