यूज़र इंटरफ़ेस (यूआई) का काम, स्क्रीन पर ऐप्लिकेशन का डेटा दिखाना है. यूज़र इंटरफ़ेस (यूआई) का इस्तेमाल, उपयोगकर्ता के साथ इंटरैक्ट करने के लिए भी किया जाता है. जब भी डेटा में बदलाव होता है, तो यूज़र इंटरफ़ेस (यूआई) में भी बदलाव दिखता है. डेटा में बदलाव, उपयोगकर्ता के इंटरैक्शन (जैसे कि बटन दबाना) या बाहरी इनपुट (जैसे कि नेटवर्क रिस्पॉन्स) की वजह से हो सकता है. असल में, यूज़र इंटरफ़ेस (यूआई), ऐप्लिकेशन की स्थिति को विज़ुअल तौर पर दिखाता है. यह स्थिति, डेटा लेयर से मिलती है.
हालांकि, डेटा लेयर से मिलने वाला ऐप्लिकेशन डेटा आम तौर पर, उस जानकारी से अलग फ़ॉर्मैट में होता है जिसे आपको दिखाना है. उदाहरण के लिए, ऐसा हो सकता है कि आपको यूज़र इंटरफ़ेस (यूआई) के लिए सिर्फ़ डेटा के कुछ हिस्से की ज़रूरत हो. इसके अलावा, ऐसा भी हो सकता है कि आपको उपयोगकर्ता के लिए काम की जानकारी दिखाने के लिए, दो अलग-अलग डेटा सोर्स को मर्ज करना पड़े. आपने जो भी लॉजिक इस्तेमाल किया है उससे कोई फ़र्क़ नहीं पड़ता. आपको यूज़र इंटरफ़ेस (यूआई) को वह सारी जानकारी देनी होगी जो उसे पूरी तरह से रेंडर करने के लिए ज़रूरी है. यूज़र इंटरफ़ेस (यूआई) लेयर, एक ऐसी पाइपलाइन होती है जो ऐप्लिकेशन के डेटा में हुए बदलावों को ऐसे फ़ॉर्म में बदलती है जिसे यूज़र इंटरफ़ेस (यूआई) दिखा सके. इसके बाद, यह उसे दिखाती है.
सामान्य केस स्टडी
मान लें कि कोई ऐसा ऐप्लिकेशन है जो किसी व्यक्ति के लिए, समाचार लेखों को फ़ेच करता है, ताकि वह उन्हें पढ़ सके. इस ऐप्लिकेशन में एक लेखों वाली स्क्रीन है. इस पर पढ़ने के लिए उपलब्ध लेख दिखाए जाते हैं. साथ ही, साइन इन किए हुए लोग उन लेखों को बुकमार्क कर सकते हैं जो उन्हें वाकई पसंद आए. किसी भी समय कई लेख उपलब्ध हो सकते हैं. इसलिए, पाठक के पास लेखों को कैटगरी के हिसाब से ब्राउज़ करने का विकल्प होना चाहिए. संक्षेप में, इस ऐप्लिकेशन की मदद से ये काम किए जा सकते हैं:
- पढ़ने के लिए उपलब्ध लेख देखें.
- कैटगरी के हिसाब से लेख ब्राउज़ करें.
- साइन इन करें और कुछ लेखों को बुकमार्क करें.
- ज़रूरी शर्तें पूरी करने पर, कुछ प्रीमियम सुविधाओं का ऐक्सेस पाएं.
यहां दिए गए सेक्शन में, इस उदाहरण को केस स्टडी के तौर पर इस्तेमाल किया गया है. इससे एकतरफ़ा डेटा फ़्लो के सिद्धांतों के बारे में जानकारी मिलती है. साथ ही, यह भी पता चलता है कि ये सिद्धांत, यूज़र इंटरफ़ेस (यूआई) लेयर के लिए ऐप्लिकेशन आर्किटेक्चर के संदर्भ में किन समस्याओं को हल करने में मदद करते हैं.
यूज़र इंटरफ़ेस लेयर का आर्किटेक्चर
यूज़र इंटरफ़ेस (यूआई) शब्द का मतलब, यूज़र इंटरफ़ेस (यूआई) एलिमेंट से है. जैसे, कंटेनर और कंपोज़ेबल फ़ंक्शन, जो डेटा दिखाते हैं. Android यूज़र इंटरफ़ेस (यूआई) बनाने के लिए, Jetpack Compose टूलकिट का इस्तेमाल करने का सुझाव दिया जाता है. डेटा लेयर की भूमिका, ऐप्लिकेशन के डेटा को सेव करना, मैनेज करना, और उसका ऐक्सेस देना है. इसलिए, यूज़र इंटरफ़ेस लेयर को यह तरीका अपनाना होगा:
- ऐप्लिकेशन डेटा का इस्तेमाल करना और उसे ऐसे डेटा में बदलना जिसे यूज़र इंटरफ़ेस आसानी से रेंडर कर सके.
- यूज़र इंटरफ़ेस (यूआई) में रेंडर किए जा सकने वाले डेटा का इस्तेमाल करता है और उसे यूज़र इंटरफ़ेस (यूआई) एलिमेंट में बदलता है, ताकि उपयोगकर्ता को दिखाया जा सके.
- इकट्ठा किए गए उन यूज़र इंटरफ़ेस (यूआई) एलिमेंट से, उपयोगकर्ता के इनपुट इवेंट का इस्तेमाल करें. साथ ही, ज़रूरत के मुताबिक यूआई डेटा में उनके असर को दिखाएं.
- जब तक ज़रूरी हो, पहले से लेकर तीसरे चरण को दोहराएं.
इस गाइड के बाकी हिस्से में, यूज़र इंटरफ़ेस (यूआई) लेयर को लागू करने का तरीका बताया गया है. यह लेयर इन चरणों को पूरा करती है. खास तौर पर, इस गाइड में इन कामों और सिद्धांतों के बारे में बताया गया है:
- यूज़र इंटरफ़ेस (यूआई) की स्थिति तय करने का तरीका
- यूज़र इंटरफ़ेस (यूआई) की स्थिति को जनरेट और मैनेज करने के लिए, एकतरफ़ा डेटा फ़्लो (यूडीएफ़)
- यूडीएफ़ के सिद्धांतों के मुताबिक, ऑब्ज़र्वेबल डेटा टाइप के साथ यूज़र इंटरफ़ेस (यूआई) की स्थिति को कैसे दिखाया जाए
- ऐसे यूज़र इंटरफ़ेस (यूआई) को लागू करने का तरीका जो यूज़र इंटरफ़ेस (यूआई) की देखी जा सकने वाली स्थिति का इस्तेमाल करता है
इनमें सबसे बुनियादी सिद्धांत, यूज़र इंटरफ़ेस (यूआई) की स्थिति की परिभाषा है.
यूज़र इंटरफ़ेस (यूआई) की स्थिति तय करना
ऊपर बताई गई केस स्टडी में, यूज़र इंटरफ़ेस (यूआई) में लेखों की सूची दिखती है. साथ ही, हर लेख के लिए कुछ मेटाडेटा भी दिखता है. ऐप्लिकेशन, उपयोगकर्ता को जो जानकारी दिखाता है वह यूज़र इंटरफ़ेस (यूआई) की स्थिति होती है.
दूसरे शब्दों में, अगर यूज़र इंटरफ़ेस (यूआई) वह है जो उपयोगकर्ता को दिखता है, तो यूआई की स्थिति वह होती है जो ऐप्लिकेशन के हिसाब से उपयोगकर्ता को दिखनी चाहिए. यूआई और यूआई की स्थिति, एक ही सिक्के के दो पहलू हैं. यूआई की स्थिति, यूआई का विज़ुअल प्रज़ेंटेशन होती है. यूज़र इंटरफ़ेस (यूआई) की स्थिति में होने वाले किसी भी बदलाव को यूज़र इंटरफ़ेस (यूआई) में तुरंत दिखाया जाता है.
इस केस स्टडी पर विचार करें: News ऐप्लिकेशन की ज़रूरी शर्तों को पूरा करने के लिए, यूज़र इंटरफ़ेस (यूआई) को पूरी तरह से रेंडर करने के लिए ज़रूरी जानकारी को NewsUiState डेटा क्लास में शामिल किया जा सकता है. इसे इस तरह से तय किया गया है:
data class NewsUiState(
val isSignedIn: Boolean = false,
val isPremium: Boolean = false,
val newsItems: List<NewsItemUiState> = listOf(),
val userMessages: List<Message> = listOf()
)
data class NewsItemUiState(
val title: String,
val body: String,
val bookmarked: Boolean = false,
...
)
यूज़र इंटरफ़ेस (यूआई) की स्थिति के बारे में ज़्यादा जानने के लिए, स्टेट और Jetpack Compose लेख पढ़ें.
इम्यूटेबिलिटी
पिछले उदाहरण में, यूज़र इंटरफ़ेस (यूआई) की स्थिति की परिभाषा में बदलाव नहीं किया जा सकता. इसका मुख्य फ़ायदा यह है कि इम्यूटेबल ऑब्जेक्ट, किसी समय पर ऐप्लिकेशन की स्थिति के बारे में गारंटी देते हैं. इससे यूज़र इंटरफ़ेस (यूआई) को अपनी मुख्य भूमिका पर फ़ोकस करने में मदद मिलती है. इसकी मुख्य भूमिका, स्थिति को पढ़ना और उसके हिसाब से यूज़र इंटरफ़ेस (यूआई) एलिमेंट को अपडेट करना है. यूज़र इंटरफ़ेस (यूआई) की स्थिति में सीधे तौर पर कभी बदलाव न करें. ऐसा तब तक न करें, जब तक यूज़र इंटरफ़ेस (यूआई) खुद अपने डेटा का एकमात्र सोर्स न हो. इस सिद्धांत का उल्लंघन करने पर, एक ही जानकारी के लिए कई सोर्स उपलब्ध हो जाते हैं. इससे डेटा में अंतर आ जाता है और मामूली गड़बड़ियां हो जाती हैं.
उदाहरण के लिए, पहले वाली केस स्टडी देखें.
अगर यूज़र इंटरफ़ेस (यूआई) की स्थिति वाले NewsItemUiState ऑब्जेक्ट में मौजूद bookmarked फ़्लैग को Activity क्लास में अपडेट किया जाता है, तो यह फ़्लैग, डेटा लेयर के साथ प्रतिस्पर्धा करता है. ऐसा इसलिए, क्योंकि यह फ़्लैग किसी लेख के बुकमार्क किए गए स्टेटस का सोर्स होता है. इस तरह की गड़बड़ी को रोकने के लिए, इम्यूटेबल डेटा क्लास बहुत काम की होती हैं.
इस गाइड में नेमिंग कनवेंशन
इस गाइड में, यूज़र इंटरफ़ेस (यूआई) की स्थिति बताने वाली क्लास के नाम, स्क्रीन या स्क्रीन के उस हिस्से की सुविधा के आधार पर रखे गए हैं जिसके बारे में वे बताती हैं. कन्वेंशन इस तरह है:
functionality + UiState.
उदाहरण के लिए, खबरों को दिखाने वाली स्क्रीन की स्थिति को NewsUiState कहा जा सकता है. साथ ही, खबरों की सूची में मौजूद किसी खबर की स्थिति को NewsItemUiState कहा जा सकता है.
एकतरफ़ा डेटा फ़्लो का इस्तेमाल करके स्थिति मैनेज करना
पिछले सेक्शन में बताया गया था कि यूज़र इंटरफ़ेस (यूआई) की स्थिति, यूआई को रेंडर करने के लिए ज़रूरी जानकारी का स्नैपशॉट है. इसमें बदलाव नहीं किया जा सकता. हालांकि, ऐप्लिकेशन में डेटा डाइनैमिक होता है. इसका मतलब है कि समय के साथ स्थिति बदल सकती है. ऐसा उपयोगकर्ता के इंटरैक्शन या अन्य इवेंट की वजह से हो सकता है. इन इवेंट से, ऐप्लिकेशन में मौजूद डेटा में बदलाव होता है.
इन इंटरैक्शन को प्रोसेस करने के लिए, मीडिएटर का इस्तेमाल किया जा सकता है. इससे हर इवेंट पर लागू होने वाले लॉजिक को तय किया जा सकता है. साथ ही, यूज़र इंटरफ़ेस (यूआई) की स्थिति बनाने के लिए, डेटा सोर्स को बदला जा सकता है. हालांकि, इन इंटरैक्शन और इनके लॉजिक को यूज़र इंटरफ़ेस (यूआई) में ही रखा जा सकता है. हालांकि, यूज़र इंटरफ़ेस (यूआई) पर बहुत ज़्यादा ज़िम्मेदारी होने की वजह से, यह तुरंत मुश्किल हो सकता है. इसके अलावा, इससे जांच करने की क्षमता पर भी असर पड़ सकता है, क्योंकि जनरेट किया गया कोड एक-दूसरे से जुड़ा होता है. अगर यूज़र इंटरफ़ेस (यूआई) की स्थिति बहुत आसान नहीं है, तो पक्का करें कि यूज़र इंटरफ़ेस (यूआई) की मुख्य ज़िम्मेदारी, यूज़र इंटरफ़ेस (यूआई) की स्थिति को इस्तेमाल करना और उसे दिखाना हो.
इस सेक्शन में, एकतरफ़ा डेटा फ़्लो (यूडीएफ़) के बारे में बताया गया है. यह एक आर्किटेक्चर पैटर्न है. इससे ज़िम्मेदारियों को अलग-अलग करने में मदद मिलती है.
स्टेट होल्डर
स्टेट होल्डर, ऐसी क्लास होती हैं जो यूज़र इंटरफ़ेस (यूआई) की स्थिति को जनरेट करने के लिए ज़िम्मेदार होती हैं. साथ ही, ये उस स्थिति को जनरेट करने के लिए ज़रूरी लॉजिक भी उपलब्ध कराती हैं. स्टेट होल्डर अलग-अलग साइज़ के होते हैं. यह इस बात पर निर्भर करता है कि वे मैनेज किए जा रहे यूज़र इंटरफ़ेस (यूआई) एलिमेंट के स्कोप के हिसाब से कितने बड़े हैं. जैसे, बॉटम ऐप्लिकेशन बार जैसे किसी एक विजेट से लेकर पूरी स्क्रीन या नेविगेशन डेस्टिनेशन तक.
दूसरे मामले में, आम तौर पर ViewModel का इंस्टेंस लागू किया जाता है. हालांकि, ऐप्लिकेशन की ज़रूरतों के हिसाब से, एक सामान्य क्लास भी काफ़ी हो सकती है. उदाहरण के लिए, केस स्टडी में दिए गए News ऐप्लिकेशन में, NewsViewModel क्लास का इस्तेमाल स्टेट होल्डर के तौर पर किया जाता है. इससे उस सेक्शन में दिखने वाली स्क्रीन के लिए यूज़र इंटरफ़ेस (यूआई) की स्थिति जनरेट होती है.
यूज़र इंटरफ़ेस (यूआई) और उसके स्टेट प्रोड्यूसर के बीच को-डिपेंडेंसी को मॉडल करने के कई तरीके हैं. हालांकि, यूज़र इंटरफ़ेस (यूआई) और इसकी ViewModel क्लास के बीच इंटरैक्शन को, इवेंट इनपुट और इसके बाद की स्थिति आउटपुट के तौर पर समझा जा सकता है. इसलिए, इस संबंध को नीचे दिए गए डायग्राम में दिखाया गया है:
जिस पैटर्न में स्टेट नीचे की ओर और इवेंट ऊपर की ओर फ़्लो होते हैं उसे एकतरफ़ा डेटा फ़्लो (यूडीएफ़) कहा जाता है. ऐप्लिकेशन के आर्किटेक्चर पर इस पैटर्न का असर इस तरह पड़ता है:
- ViewModel, यूज़र इंटरफ़ेस (यूआई) के इस्तेमाल के लिए स्टेट को सेव करता है और उसे दिखाता है. यूज़र इंटरफ़ेस (यूआई) की स्थिति, ऐप्लिकेशन का ऐसा डेटा होता है जिसे ViewModel ट्रांसफ़ॉर्म करता है.
- यूज़र इंटरफ़ेस, उपयोगकर्ता के इवेंट की सूचना ViewModel को देता है.
- ViewModel, उपयोगकर्ता की कार्रवाइयों को मैनेज करता है और स्थिति को अपडेट करता है.
- अपडेट की गई स्थिति को यूज़र इंटरफ़ेस (यूआई) में वापस भेज दिया जाता है, ताकि उसे रेंडर किया जा सके.
- ऊपर दी गई प्रोसेस को ऐसे हर इवेंट के लिए दोहराया जाता है जिससे स्थिति में बदलाव होता है.
नेविगेशन डेस्टिनेशन या स्क्रीन के लिए, ViewModel, डेटा पाने के लिए रिपॉज़िटरी या यूज़ केस क्लास के साथ काम करता है. साथ ही, डेटा को यूज़र इंटरफ़ेस (यूआई) की स्थिति में बदलता है. ऐसा करते समय, यह उन इवेंट के असर को शामिल करता है जिनकी वजह से स्थिति में बदलाव हो सकता है. ऊपर बताई गई केस स्टडी में लेखों की एक सूची होती है. हर लेख में ये जानकारी होती है: टाइटल, ब्यौरा, सोर्स, लेखक का नाम, पब्लिकेशन की तारीख, और लेख को बुकमार्क किया गया है या नहीं. हर लेख आइटम के लिए यूज़र इंटरफ़ेस (यूआई) ऐसा दिखता है:
किसी लेख को बुकमार्क करने का अनुरोध करने वाला उपयोगकर्ता, ऐसे इवेंट का उदाहरण है जिससे स्टेट में बदलाव हो सकते हैं. स्टेट प्रोड्यूसर के तौर पर, ViewModel की यह ज़िम्मेदारी है कि वह यूज़र इंटरफ़ेस (यूआई) की स्थिति में सभी फ़ील्ड भरने के लिए ज़रूरी लॉजिक तय करे. साथ ही, यूज़र इंटरफ़ेस (यूआई) को पूरी तरह से रेंडर करने के लिए ज़रूरी इवेंट प्रोसेस करे.
यहां दिए गए सेक्शन में, उन इवेंट के बारे में ज़्यादा जानकारी दी गई है जिनकी वजह से स्थिति में बदलाव होता है. साथ ही, यह भी बताया गया है कि यूडीएफ़ का इस्तेमाल करके उन्हें कैसे प्रोसेस किया जा सकता है.
तर्क के टाइप
किसी लेख को बुकमार्क करना, कारोबार के लॉजिक का एक उदाहरण है. ऐसा इसलिए, क्योंकि इससे आपके ऐप्लिकेशन को फ़ायदा मिलता है. इसके बारे में ज़्यादा जानने के लिए, डेटा लेयर पेज देखें. हालांकि, अलग-अलग तरह के लॉजिक होते हैं जिन्हें तय करना ज़रूरी होता है:
- कारोबारी नियम, ऐप्लिकेशन के डेटा के लिए प्रॉडक्ट की ज़रूरी शर्तों को लागू करने की प्रोसेस है. जैसा कि पहले बताया गया है, इसका एक उदाहरण केस स्टडी ऐप्लिकेशन में किसी लेख को बुकमार्क करना है. कारोबार से जुड़ा लॉजिक आम तौर पर डोमेन या डेटा लेयर में रखा जाता है, लेकिन यूज़र इंटरफ़ेस (यूआई) लेयर में कभी नहीं रखा जाता.
- यूज़र इंटरफ़ेस (यूआई) के व्यवहार का लॉजिक या यूज़र इंटरफ़ेस (यूआई) का लॉजिक, स्क्रीन पर स्थिति में हुए बदलावों को कैसे दिखाया जाए, यह तय करता है. उदाहरण के लिए, Android
Resourcesका इस्तेमाल करके, स्क्रीन पर दिखाने के लिए सही टेक्स्ट पाना, उपयोगकर्ता के किसी बटन पर क्लिक करने पर किसी खास स्क्रीन पर जाना या टोस्ट या स्नैकबार का इस्तेमाल करके, स्क्रीन पर उपयोगकर्ता का मैसेज दिखाना.
यूज़र इंटरफ़ेस (यूआई) के लॉजिक को यूज़र इंटरफ़ेस (यूआई) में रखें, न कि ViewModel में. खास तौर पर, जब इसमें Context जैसे यूज़र इंटरफ़ेस (यूआई) टाइप शामिल हों.
अगर यूज़र इंटरफ़ेस (यूआई) ज़्यादा जटिल हो जाता है और आपको यूज़र इंटरफ़ेस (यूआई) लॉजिक को किसी दूसरी क्लास को सौंपना है, ताकि टेस्ट करने में आसानी हो और अलग-अलग काम अलग-अलग क्लास में किए जा सकें, तो स्टेट होल्डर के तौर पर एक सामान्य क्लास बनाई जा सकती है. यूज़र इंटरफ़ेस (यूआई) में बनाई गई सामान्य क्लास, Android SDK की डिपेंडेंसी ले सकती हैं, क्योंकि वे यूज़र इंटरफ़ेस (यूआई) के लाइफ़साइकल को फ़ॉलो करती हैं. वहीं, ViewModel ऑब्जेक्ट का लाइफ़साइकल लंबा होता है.
स्टेट होल्डर और यूज़र इंटरफ़ेस (यूआई) बनाने में उनकी भूमिका के बारे में ज़्यादा जानने के लिए, Jetpack Compose स्टेट गाइड देखें.
यूडीएफ़ का इस्तेमाल क्यों करें?
यूडीएफ़, राज्य के उत्पादन के चक्र को मॉडल करता है. इसे चौथी इमेज में दिखाया गया है. यह उस जगह को भी अलग करता है जहां से स्थिति में बदलाव शुरू होते हैं, जहां उन्हें बदला जाता है, और जहां उनका आखिर में इस्तेमाल किया जाता है. इस तरह से अलग करने पर, यूज़र इंटरफ़ेस (यूआई) ठीक वही काम करता है जो इसके नाम से पता चलता है: स्थिति में हुए बदलावों को देखकर जानकारी दिखाना. साथ ही, उन बदलावों को ViewModel को पास करके, उपयोगकर्ता के इरादे को आगे बढ़ाना.
दूसरे शब्दों में, यूडीएफ़ की मदद से ये काम किए जा सकते हैं:
- डेटा में एकरूपता. यूज़र इंटरफ़ेस (यूआई) के लिए, एक ही भरोसेमंद सोर्स होता है.
- नतीजे जांचे जाने की योग्यता. स्टेट का सोर्स अलग किया गया है. इसलिए, इसे यूज़र इंटरफ़ेस (यूआई) से अलग टेस्ट किया जा सकता है.
- रखरखाव में आसानी. स्टेट में बदलाव, तय किए गए पैटर्न के हिसाब से होता है. इसमें, उपयोगकर्ता के इवेंट और डेटा के सोर्स, दोनों की वजह से बदलाव होते हैं.
यूज़र इंटरफ़ेस (यूआई) की स्थिति को सार्वजनिक करना
यूज़र इंटरफ़ेस (यूआई) की स्थिति तय करने और यह तय करने के बाद कि उस स्थिति को कैसे मैनेज किया जाएगा, अगला चरण यूज़र इंटरफ़ेस (यूआई) को उस स्थिति के बारे में बताना है.
स्टेट के प्रोडक्शन को मैनेज करने के लिए यूडीएफ़ का इस्तेमाल करते समय, प्रोड्यूस की गई स्टेट को स्ट्रीम माना जा सकता है. दूसरे शब्दों में कहें, तो समय के साथ स्टेट के कई वर्शन प्रोड्यूस किए जाते हैं. यूज़र इंटरफ़ेस (यूआई) की स्थिति को StateFlow जैसे ऑब्ज़र्वेबल डेटा होल्डर में दिखाएं. इससे यूज़र इंटरफ़ेस (यूआई), स्थिति में हुए किसी भी बदलाव पर प्रतिक्रिया कर पाता है. इसके लिए, उसे ViewModel से डेटा को मैन्युअल तरीके से सीधे तौर पर पुल करने की ज़रूरत नहीं पड़ती. इसका यह भी फ़ायदा है कि यूज़र इंटरफ़ेस (यूआई) की स्थिति का सबसे नया वर्शन हमेशा कैश मेमोरी में सेव रहता है. यह कॉन्फ़िगरेशन में बदलाव के बाद, स्थिति को तुरंत पहले जैसा करने के लिए फ़ायदेमंद होता है.
class NewsViewModel(...) : ViewModel() {
val uiState: NewsUiState = …
}
Kotlin फ़्लो के बारे में जानने के लिए, Android पर Kotlin फ़्लो लेख पढ़ें.
StateFlow को ऑब्ज़र्वेबल डेटा होल्डर के तौर पर इस्तेमाल करने का तरीका जानने के लिए,
Jetpack Compose में ऐडवांस स्टेट और साइड इफ़ेक्ट कोडलैब देखें.
अगर यूज़र इंटरफ़ेस (यूआई) को दिखाया गया डेटा आसान है, तो अक्सर डेटा को यूज़र इंटरफ़ेस (यूआई) की स्थिति के टाइप में रैप करना फ़ायदेमंद होता है. ऐसा इसलिए, क्योंकि इससे स्टेट होल्डर और उससे जुड़ी स्क्रीन या यूज़र इंटरफ़ेस (यूआई) एलिमेंट के बीच के संबंध के बारे में पता चलता है. यूज़र इंटरफ़ेस (यूआई) एलिमेंट के ज़्यादा जटिल होने पर, इसे यूज़र इंटरफ़ेस (यूआई) की स्थिति की परिभाषा में आसानी से जोड़ा जा सकता है. इससे, यूज़र इंटरफ़ेस (यूआई) एलिमेंट को रेंडर करने के लिए ज़रूरी अतिरिक्त जानकारी को शामिल किया जा सकता है.
UiState की स्ट्रीम बनाने का एक सामान्य तरीका यह है कि private set के साथ mutableStateOf प्रॉपर्टी को दिखाया जाए. साथ ही, ViewModel में स्थिति को बदला जा सके, लेकिन यूज़र इंटरफ़ेस (यूआई) के लिए इसे सिर्फ़ पढ़ने के लिए उपलब्ध कराया जाए.
class NewsViewModel(...) : ViewModel() {
var uiState by mutableStateOf(NewsUiState())
private set
...
}
इसके बाद, ViewModel ऐसे तरीके दिखा सकता है जो अंदरूनी तौर पर स्थिति में बदलाव करते हैं. साथ ही, यूज़र इंटरफ़ेस (यूआई) के इस्तेमाल के लिए अपडेट पब्लिश करते हैं. उदाहरण के लिए, मान लें कि आपको एसिंक्रोनस कार्रवाई करनी है.
viewModelScope का इस्तेमाल करके कोरूटीन लॉन्च की जा सकती है. इसके बाद, पूरा होने पर बदलने वाली स्थिति को अपडेट किया जा सकता है.
class NewsViewModel(
private val repository: NewsRepository,
...
) : ViewModel() {
var uiState by mutableStateOf(NewsUiState())
private set
private var fetchJob: Job? = null
fun fetchArticles(category: String) {
fetchJob?.cancel()
fetchJob = viewModelScope.launch {
try {
val newsItems = repository.newsItemsForCategory(category)
uiState = uiState.copy(newsItems = newsItems)
} catch (ioe: IOException) {
// Handle the error and notify the UI when appropriate.
val messages = getMessagesFromThrowable(ioe)
uiState = uiState.copy(userMessages = messages)
}
}
}
}
ऊपर दिए गए उदाहरण में, NewsViewModel क्लास किसी कैटगरी के लिए लेख फ़ेच करने की कोशिश करती है. इसके बाद, कोशिश के नतीजे को यूज़र इंटरफ़ेस (यूआई) की स्थिति में दिखाती है. इससे यूज़र इंटरफ़ेस (यूआई) इस पर सही तरीके से प्रतिक्रिया दे सकता है.
गड़बड़ी ठीक करने के बारे में ज़्यादा जानकारी के लिए, स्क्रीन पर गड़बड़ियां दिखाना सेक्शन देखें.
ज़्यादा जानकारी
यूज़र इंटरफ़ेस (यूआई) की स्थिति को दिखाने के लिए, यहां दिए गए दिशा-निर्देशों का पालन करें.
एक-दूसरे से जुड़ी स्थितियों को मैनेज करने के लिए, यूज़र इंटरफ़ेस (यूआई) की स्थिति वाले एक ऑब्जेक्ट का इस्तेमाल करें. इससे कोड में कम अंतर होता है और इसे समझना आसान हो जाता है. अगर आपने खबरों की सूची और बुकमार्क की संख्या को दो अलग-अलग स्ट्रीम में दिखाया है, तो ऐसा हो सकता है कि एक स्ट्रीम अपडेट हो गई हो और दूसरी नहीं. एक स्ट्रीम का इस्तेमाल करने पर, दोनों एलिमेंट अपडेट होते रहते हैं. इसके अलावा, कुछ कारोबारी लॉजिक के लिए, सोर्स के कॉम्बिनेशन की ज़रूरत पड़ सकती है. उदाहरण के लिए, आपको सिर्फ़ तब बुकमार्क बटन दिखाना पड़ सकता है, जब उपयोगकर्ता ने साइन इन किया हो और वह प्रीमियम न्यूज़ सर्विस का सदस्य हो. यूज़र इंटरफ़ेस (यूआई) स्टेट क्लास को इस तरह से तय किया जा सकता है:
data class NewsUiState( val isSignedIn: Boolean = false, val isPremium: Boolean = false, val newsItems: List<NewsItemUiState> = listOf() ) val NewsUiState.canBookmarkNews: Boolean get() = isSignedIn && isPremiumइस एलान में, बुकमार्क बटन के दिखने की सुविधा, दो अन्य प्रॉपर्टी से मिली हुई प्रॉपर्टी है. कारोबार के नियम ज़्यादा जटिल होने पर, एक ऐसी
UiStateक्लास का होना ज़रूरी हो जाता है जिसमें सभी प्रॉपर्टी तुरंत उपलब्ध हों.यूज़र इंटरफ़ेस (यूआई) की स्थितियां: एक स्ट्रीम या कई स्ट्रीम? यूज़र इंटरफ़ेस (यूआई) की स्थिति को एक स्ट्रीम में दिखाना है या कई स्ट्रीम में, यह तय करने के लिए मुख्य सिद्धांत यह है कि एमिट किए गए आइटम के बीच क्या संबंध है. एक ही स्ट्रीम से डेटा पाने के ये फ़ायदे हैं: सुविधा और डेटा में एकरूपता. इससे राज्य के उपभोक्ताओं को हमेशा नई जानकारी मिलती रहती है. हालांकि, कुछ ऐसे उदाहरण हैं जिनमें ViewModel से राज्य की अलग-अलग स्ट्रीम का इस्तेमाल करना सही हो सकता है:
अलग-अलग डेटा टाइप: यूज़र इंटरफ़ेस (यूआई) को रेंडर करने के लिए ज़रूरी कुछ स्टेट, एक-दूसरे से पूरी तरह अलग हो सकती हैं. ऐसे मामलों में, इन अलग-अलग राज्यों को एक साथ बंडल करने की लागत, इससे मिलने वाले फ़ायदों से ज़्यादा हो सकती है. ऐसा खास तौर पर तब होता है, जब इनमें से कोई एक राज्य दूसरे राज्य की तुलना में ज़्यादा बार अपडेट होता है.
UiStateअंतर: किसीUiStateऑब्जेक्ट में जितने ज़्यादा फ़ील्ड होंगे, स्ट्रीम के किसी फ़ील्ड के अपडेट होने की वजह से स्ट्रीम के रिलीज़ होने की संभावना उतनी ही ज़्यादा होगी. यूज़र इंटरफ़ेस (यूआई) एलिमेंट में, यह समझने के लिए कोई डिफ़रेंसिंग मैकेनिज़्म नहीं होता कि लगातार होने वाले उत्सर्जन अलग-अलग हैं या एक जैसे. इसलिए, हर उत्सर्जन से यूज़र इंटरफ़ेस (यूआई) एलिमेंट अपडेट होता है. इसका मतलब है किFlowएपीआई के तरीकों, जैसे किdistinctUntilChanged()का इस्तेमाल करके, समस्या को कम करना ज़रूरी हो सकता है.
रेंडरिंग और यूज़र इंटरफ़ेस (यूआई) की स्थिति के बारे में ज़्यादा जानने के लिए, कंपोज़ेबल का लाइफ़साइकल लेख पढ़ें.
यूज़र इंटरफ़ेस (यूआई) की स्थिति का इस्तेमाल करना
यूज़र इंटरफ़ेस (यूआई) में UiState ऑब्जेक्ट की स्ट्रीम का इस्तेमाल करने के लिए, इस्तेमाल किए जा रहे ऑब्ज़र्वेबल डेटा टाइप के लिए टर्मिनल ऑपरेटर का इस्तेमाल करें. उदाहरण के लिए, Kotlin फ़्लो के लिए collect() तरीके या इसके वैरिएंट का इस्तेमाल करें.
यूज़र इंटरफ़ेस (यूआई) में ऑब्ज़र्वेबल डेटा होल्डर का इस्तेमाल करते समय, यूज़र इंटरफ़ेस (यूआई) के लाइफ़साइकल का ध्यान रखें. जब कंपोज़ेबल को उपयोगकर्ता को नहीं दिखाया जा रहा हो, तब यूज़र इंटरफ़ेस (यूआई) को यूज़र इंटरफ़ेस (यूआई) की स्थिति पर नज़र रखने की अनुमति न दें. इस विषय के बारे में ज़्यादा जानने के लिए, यह ब्लॉग पोस्ट पढ़ें. फ़्लो का इस्तेमाल करते समय, लाइफ़साइकल से जुड़ी समस्याओं को हल करने के लिए, सही कोरूटीन स्कोप और collectAsStateWithLifecycle एपीआई का इस्तेमाल करना सबसे अच्छा होता है:
@Composable private fun ConversationScreen( conversationViewModel: ConversationViewModel = viewModel() ) { val messages by conversationViewModel.messages.collectAsStateWithLifecycle() ConversationScreen( messages = messages, onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) } ) } @Composable private fun ConversationScreen( messages: List<Message>, onSendMessage: (Message) -> Unit ) { MessagesList(messages, onSendMessage) /* ... */ }
चल रही कार्रवाइयां दिखाएं
UiState क्लास में लोडिंग की स्थितियां दिखाने का आसान तरीका, बूलियन फ़ील्ड का इस्तेमाल करना है:
data class NewsUiState(
val isFetchingArticles: Boolean = false,
...
)
इस फ़्लैग की वैल्यू से पता चलता है कि यूज़र इंटरफ़ेस (यूआई) में प्रोग्रेस बार मौजूद है या नहीं.
@Composable
fun LatestNewsScreen(
modifier: Modifier = Modifier,
viewModel: NewsViewModel = viewModel()
) {
Box(modifier.fillMaxSize()) {
if (viewModel.uiState.isFetchingArticles) {
CircularProgressIndicator(Modifier.align(Alignment.Center))
}
// Add other UI elements. For example, the list.
}
}
स्क्रीन पर गड़बड़ियां दिखाएं
यूज़र इंटरफ़ेस (यूआई) में गड़बड़ियां दिखाना, प्रोसेस में मौजूद कार्रवाइयों को दिखाने जैसा ही है. ऐसा इसलिए, क्योंकि दोनों को बूलियन वैल्यू से आसानी से दिखाया जा सकता है. ये वैल्यू, गड़बड़ियों या कार्रवाइयों के मौजूद होने या न होने के बारे में बताती हैं. हालांकि, गड़बड़ियों में उपयोगकर्ता को वापस भेजने के लिए, उनसे जुड़ा मैसेज भी शामिल हो सकता है. इसके अलावा, उनसे जुड़ी कोई ऐसी कार्रवाई भी शामिल हो सकती है जो पूरी नहीं हुई कार्रवाई को फिर से करने की कोशिश करती है. इसलिए, जब कोई ऑपरेशन चल रहा हो और वह लोड हो रहा हो या लोड न हो रहा हो, तो गड़बड़ी की स्थितियों को डेटा क्लास के साथ मॉडल किया जा सकता है. ये डेटा क्लास, गड़बड़ी के कॉन्टेक्स्ट के लिए सही मेटाडेटा होस्ट करती हैं.
पिछले उदाहरण पर विचार करें, जिसमें लेखों को फ़ेच करते समय प्रोग्रेस बार दिखाया गया था. अगर इस कार्रवाई के दौरान कोई गड़बड़ी होती है, तो आपको उपयोगकर्ता को एक या उससे ज़्यादा मैसेज दिखाने पड़ सकते हैं. इनमें गड़बड़ी की वजह के बारे में बताया जाता है.
data class Message(val id: Long, val message: String)
data class NewsUiState(
val userMessages: List<Message> = listOf(),
...
)
इसके बाद, गड़बड़ी के मैसेज को यूज़र इंटरफ़ेस (यूआई) एलिमेंट के तौर पर दिखाया जा सकता है. जैसे, स्नैकबार. यूज़र इंटरफ़ेस (यूआई) इवेंट कैसे जनरेट होते हैं और उनका इस्तेमाल कैसे किया जाता है, इस बारे में ज़्यादा जानने के लिए यूज़र इंटरफ़ेस (यूआई) इवेंट लेख पढ़ें.
थ्रेडिंग और कॉंकुरेंसी
पक्का करें कि ViewModel में किया गया सारा काम main-safe हो. इसका मतलब है कि इसे मुख्य थ्रेड से कॉल किया जा सकता है. डेटा और डोमेन लेयर, काम को किसी दूसरे थ्रेड पर ले जाने के लिए ज़िम्मेदार होती हैं.
अगर कोई ViewModel लंबे समय तक चलने वाले ऑपरेशन करता है, तो वह उस लॉजिक को बैकग्राउंड थ्रेड में ले जाने के लिए भी ज़िम्मेदार होता है. Kotlin कोरूटीन, एक साथ कई कार्रवाइयों को मैनेज करने का बेहतरीन तरीका है. साथ ही, Jetpack Architecture Components में इनके लिए पहले से ही सपोर्ट मौजूद है. Android ऐप्लिकेशन में कोरूटीन इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, Android पर Kotlin कोरूटीन लेख पढ़ें.
नेविगेशन
ऐप्लिकेशन नेविगेशन में बदलाव अक्सर इवेंट जैसे उत्सर्जन की वजह से होते हैं. उदाहरण के लिए, SignInViewModel क्लास के साइन इन करने के बाद, UiState में isSignedIn फ़ील्ड को true पर सेट किया जा सकता है. इन ट्रिगर का इस्तेमाल, Consume UI state सेक्शन में बताए गए ट्रिगर की तरह ही करें. हालांकि, Navigation component में, ट्रिगर के इस्तेमाल को कुछ समय के लिए रोक दें.
यूज़र इंटरफ़ेस (यूआई) नेविगेशन के बारे में ज़्यादा जानने के लिए, Navigation 3 देखें.
पृष्ठांकन
Paging library का इस्तेमाल यूज़र इंटरफ़ेस (यूआई) में किया जाता है. इसका टाइप PagingData होता है. PagingData
ऐसे आइटम दिखाता है जिनमें समय के साथ बदलाव हो सकता है. दूसरे शब्दों में कहें, तो यह
बदला नहीं जा सकने वाला टाइप नहीं है. इसलिए, इसे यूज़र इंटरफ़ेस (यूआई) की ऐसी स्थिति में न दिखाएं जिसमें बदलाव नहीं किया जा सकता.
इसके बजाय, इसे ViewModel से अलग से इसकी स्ट्रीम में दिखाएं.
यहां दिए गए उदाहरण में, Paging library के Compose API को दिखाया गया है:
@Composable fun MyScreen(flow: Flow<PagingData<String>>) { val lazyPagingItems = flow.collectAsLazyPagingItems() LazyColumn { items( lazyPagingItems.itemCount, key = lazyPagingItems.itemKey { it } ) { index -> val item = lazyPagingItems[index] Text("Item is $item") } } }
ऐनिमेशन
टॉप-लेवल नेविगेशन के ट्रांज़िशन को बेहतर बनाने के लिए, आपको ऐनिमेशन शुरू करने से पहले, दूसरी स्क्रीन के डेटा लोड होने का इंतज़ार करना पड़ सकता है.
नेविगेशन ट्रांज़िशन के बारे में ज़्यादा जानने के लिए, Navigation 3 और Compose में शेयर किए गए एलिमेंट के ट्रांज़िशन देखें.
अन्य संसाधन
कॉन्टेंट देखता है
सैंपल
Google के इन सैंपल से, यूज़र इंटरफ़ेस (यूआई) लेयर के इस्तेमाल के बारे में पता चलता है. इन दिशा-निर्देशों को लागू करने के तरीके के बारे में जानने के लिए, इन्हें देखें:
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक का टेक्स्ट दिखता है
- यूज़र इंटरफ़ेस (यूआई) स्टेट प्रोडक्शन
- स्टेट होल्डर और यूज़र इंटरफ़ेस (यूआई) स्टेट {:#mad-arch}
- ऐप्लिकेशन के आर्किटेक्चर की गाइड