कंपोज़ की सुविधा के बारे में सोचें

Jetpack Compose, Android के लिए एक मॉडर्न डिक्लेरेटिव यूज़र इंटरफ़ेस (यूआई) टूलकिट है. Compose, ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) को लिखने और उसे बनाए रखने की प्रोसेस को आसान बनाता है. इसके लिए, यह डिक्लेरेटिव एपीआई उपलब्ध कराता है. इसकी मदद से, फ़्रंटएंड व्यू में बदलाव किए बिना ही ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) को रेंडर किया जा सकता है. इस शब्दावली के बारे में कुछ जानकारी देना ज़रूरी है. हालांकि, इसका असर आपके ऐप्लिकेशन के डिज़ाइन पर पड़ता है.

डिक्लेरेटिव प्रोग्रामिंग पैराडाइम

पहले, Android व्यू हैरारकी को यूज़र इंटरफ़ेस (यूआई) विजेट के ट्री के तौर पर दिखाया जाता था. उपयोगकर्ता के इंटरैक्शन जैसी वजहों से, ऐप्लिकेशन की स्थिति बदलती रहती है. इसलिए, मौजूदा डेटा दिखाने के लिए यूज़र इंटरफ़ेस (यूआई) हैरारकी को अपडेट करना ज़रूरी होता है. यूज़र इंटरफ़ेस (यूआई) को अपडेट करने का सबसे सामान्य तरीका, findViewById() जैसे फ़ंक्शन का इस्तेमाल करके ट्री को अपडेट करना है. साथ ही, button.setText(String), container.addChild(View) या img.setImageBitmap(Bitmap) जैसे तरीकों को कॉल करके नोड बदलना है. इन तरीकों से, विजेट की अंदरूनी स्थिति बदल जाती है.

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

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

पूरी स्क्रीन को फिर से जनरेट करने में एक समस्या यह है कि इसमें समय, कंप्यूटिंग पावर, और बैटरी का इस्तेमाल ज़्यादा हो सकता है. इस लागत को कम करने के लिए, Compose यह तय करता है कि यूज़र इंटरफ़ेस (यूआई) के किन हिस्सों को किसी भी समय फिर से रेंडर करने की ज़रूरत है. इसका असर आपके यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट को डिज़ाइन करने के तरीके पर पड़ता है. इसके बारे में फिर से कंपोज़िशन में बताया गया है.

कंपोज़ेबल फ़ंक्शन का उदाहरण

Compose का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) बनाया जा सकता है. इसके लिए, कंपोज़ेबल फ़ंक्शन का एक सेट तय करना होता है. ये फ़ंक्शन, डेटा लेते हैं और यूज़र इंटरफ़ेस (यूआई) एलिमेंट जनरेट करते हैं. उदाहरण के लिए, Greeting विजेट, जो String लेता है और Text विजेट दिखाता है, जिसमें बधाई का मैसेज दिखता है.

फ़ोन की स्क्रीन पर, Hello World टेक्स्ट और उस कंपोज़ेबल फ़ंक्शन का कोड दिखाया गया है जो उस यूज़र इंटरफ़ेस (यूआई) को जनरेट करता है.
पहली इमेज. यह एक कंपोज़ेबल फ़ंक्शन है, जिसे डेटा पास किया जाता है. इसका इस्तेमाल स्क्रीन पर टेक्स्ट विजेट रेंडर करने के लिए किया जाता है.

इस फ़ंक्शन के बारे में कुछ ज़रूरी बातें:

  • एनोटेशन: फ़ंक्शन को @Composable एनोटेशन के साथ एनोटेट किया गया है. सभी कंपोज़ेबल फ़ंक्शन में यह एनोटेशन होना चाहिए. यह एनोटेशन, Compose कंपाइलर को बताता है कि इस फ़ंक्शन का इस्तेमाल, डेटा को यूज़र इंटरफ़ेस (यूआई) में बदलने के लिए किया जाता है.
  • डेटा इनपुट: फ़ंक्शन में डेटा डाला जाता है. कंपोज़ेबल फ़ंक्शन, पैरामीटर स्वीकार कर सकते हैं. इनकी मदद से, ऐप्लिकेशन लॉजिक, यूज़र इंटरफ़ेस (यूआई) के बारे में बताता है. इस मामले में, हमारा विजेट String स्वीकार करता है, ताकि वह उपयोगकर्ता का नाम लेकर उसे बधाई दे सके.
  • यूज़र इंटरफ़ेस (यूआई) डिसप्ले: यह फ़ंक्शन, यूज़र इंटरफ़ेस (यूआई) में टेक्स्ट दिखाता है. ऐसा करने के लिए, यह Text() कंपोज़ेबल फ़ंक्शन को कॉल करता है. यह फ़ंक्शन, टेक्स्ट यूज़र इंटरफ़ेस (यूआई) एलिमेंट बनाता है. कंपोज़ेबल फ़ंक्शन, दूसरे कंपोज़ेबल फ़ंक्शन को कॉल करके यूज़र इंटरफ़ेस (यूआई) के कॉम्पोनेंट की हैरारकी बनाते हैं.
  • कोई रिटर्न वैल्यू नहीं: यह फ़ंक्शन कोई वैल्यू नहीं दिखाता है. यूआई को दिखाने वाले Compose फ़ंक्शन को कुछ भी रिटर्न करने की ज़रूरत नहीं होती, क्योंकि वे यूआई विजेट बनाने के बजाय टारगेट स्क्रीन की स्थिति के बारे में बताते हैं.
  • प्रॉपर्टी: यह फ़ंक्शन तेज़ी से काम करता है. यह आईडंपोटेंट है और इसमें साइड-इफ़ेक्ट नहीं होते.

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

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

डिक्लेरेटिव पैराडाइम में बदलाव

कई ज़रूरी ऑब्जेक्ट-ओरिएंटेड यूज़र इंटरफ़ेस (यूआई) टूलकिट में, विजेट के ट्री को इंस्टैंटिएट करके यूआई को शुरू किया जाता है. आम तौर पर, ऐसा एक्सएमएल लेआउट फ़ाइल को बड़ा करके किया जाता है. हर विजेट अपनी इंटरनल स्थिति बनाए रखता है. साथ ही, यह getter और setter तरीके दिखाता है. इनकी मदद से, ऐप्लिकेशन लॉजिक, विजेट के साथ इंटरैक्ट कर पाता है.

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

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

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

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

डाइनैमिक कॉन्टेंट

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

@Composable
fun Greeting(names: List<String>) {
    for (name in names) {
        Text("Hello $name")
    }
}

यह फ़ंक्शन नामों की सूची लेता है और हर उपयोगकर्ता के लिए बधाई संदेश जनरेट करता है. ऐप्लिकेशन बनाने की सुविधा का इस्तेमाल करके, कई तरह के फ़ंक्शन बनाए जा सकते हैं. if स्टेटमेंट का इस्तेमाल करके, यह तय किया जा सकता है कि आपको कोई यूज़र इंटरफ़ेस (यूआई) एलिमेंट दिखाना है या नहीं. लूप का इस्तेमाल किया जा सकता है. हेल्पर फ़ंक्शन कॉल किए जा सकते हैं. आपके पास, मूल भाषा को पूरी तरह से इस्तेमाल करने का विकल्प होता है. यह सुविधा और आसानी से इस्तेमाल करने की क्षमता, Jetpack Compose के मुख्य फ़ायदों में से एक है.

फिर से कंपोज़ करना

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

उदाहरण के लिए, इस कंपोज़ेबल फ़ंक्शन पर विचार करें, जो एक बटन दिखाता है:

@Composable
fun ClickCounter(clicks: Int, onClick: () -> Unit) {
    Button(onClick = onClick) {
        Text("I've been clicked $clicks times")
    }
}

बटन पर हर बार क्लिक करने पर, कॉलर clicks की वैल्यू अपडेट करता है. नई वैल्यू दिखाने के लिए, Compose, Text फ़ंक्शन के साथ लैंबडा को फिर से कॉल करता है; इस प्रोसेस को रीकंपोज़िशन कहा जाता है. ऐसे अन्य फ़ंक्शन फिर से कंपोज़ नहीं किए जाते हैं जो वैल्यू पर निर्भर नहीं होते.

जैसा कि हमने बताया, पूरे यूआई ट्री को फिर से कंपोज़ करने में कंप्यूटेशनल पावर और बैटरी की खपत ज़्यादा हो सकती है. Compose, इस समस्या को इंटेलिजेंट रीकंपोज़िशन की मदद से हल करता है.

रीकंपोज़िशन, इनपुट में बदलाव होने पर कंपोज़ेबल फ़ंक्शन को फिर से कॉल करने की प्रोसेस है. नए इनपुट के आधार पर Compose के फिर से कंपोज़ होने पर, यह सिर्फ़ उन फ़ंक्शन या लैम्डा को कॉल करता है जिनमें बदलाव हुआ हो. साथ ही, बाकी को छोड़ देता है. पैरामीटर में बदलाव न होने पर, Compose फ़ंक्शन या लैम्ब्डा को छोड़कर, बेहतर तरीके से फिर से कंपोज़ करता है.

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

  • शेयर किए गए ऑब्जेक्ट की किसी प्रॉपर्टी में लिखना
  • ViewModel में किसी ऑब्ज़र्वेबल को अपडेट करना
  • शेयर की गई सेटिंग अपडेट की जा रही हैं

कंपोज़ेबल फ़ंक्शन को हर फ़्रेम में फिर से एक्ज़ीक्यूट किया जा सकता है. जैसे, जब कोई ऐनिमेशन रेंडर किया जा रहा हो. ऐनिमेशन के दौरान जंक से बचने के लिए, कंपोज़ेबल फ़ंक्शन तेज़ी से काम करने चाहिए. अगर आपको ज़्यादा समय लेने वाले ऑपरेशन करने हैं, जैसे कि शेयर की गई प्राथमिकताओं से डेटा पढ़ना, तो इसे बैकग्राउंड कोरूटीन में करें. साथ ही, वैल्यू के नतीजे को पैरामीटर के तौर पर कंपोज़ेबल फ़ंक्शन में पास करें.

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

@Composable
fun SharedPrefsToggle(
    text: String,
    value: Boolean,
    onValueChanged: (Boolean) -> Unit
) {
    Row {
        Text(text)
        Checkbox(checked = value, onCheckedChange = onValueChanged)
    }
}

इस दस्तावेज़ में, Compose का इस्तेमाल करते समय ध्यान रखने वाली कई बातों के बारे में बताया गया है:

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

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

रीकंपोज़िशन की प्रोसेस को ज़्यादा से ज़्यादा बार स्किप किया जाता है

जब आपके यूज़र इंटरफ़ेस (यूआई) के कुछ हिस्से अमान्य होते हैं, तो Compose सिर्फ़ उन हिस्सों को फिर से कंपोज़ करता है जिन्हें अपडेट करने की ज़रूरत होती है. इसका मतलब है कि यह यूज़र इंटरफ़ेस (यूआई) ट्री में मौजूद, ऊपर या नीचे के किसी भी कंपोज़ेबल को एक्ज़ीक्यूट किए बिना, किसी एक Button's कंपोज़ेबल को फिर से चलाने के लिए स्किप कर सकता है.

हर कंपोज़ेबल फ़ंक्शन और लैम्डा, खुद से रीकंपोज़ हो सकता है. यहां दिए गए उदाहरण में बताया गया है कि सूची रेंडर करते समय, रीकंपोज़िशन कुछ एलिमेंट को कैसे छोड़ सकता है:

/**
 * Display a list of names the user can click with a header
 */
@Composable
fun NamePicker(
    header: String,
    names: List<String>,
    onNameClicked: (String) -> Unit
) {
    Column {
        // this will recompose when [header] changes, but not when [names] changes
        Text(header, style = MaterialTheme.typography.bodyLarge)
        HorizontalDivider()

        // LazyColumn is the Compose version of a RecyclerView.
        // The lambda passed to items() is similar to a RecyclerView.ViewHolder.
        LazyColumn {
            items(names) { name ->
                // When an item's [name] updates, the adapter for that item
                // will recompose. This will not recompose when [header] changes
                NamePickerItem(name, onNameClicked)
            }
        }
    }
}

/**
 * Display a single name the user can click.
 */
@Composable
private fun NamePickerItem(name: String, onClicked: (String) -> Unit) {
    Text(name, Modifier.clickable(onClick = { onClicked(name) }))
}

रीकंपोज़िशन के दौरान, इनमें से हर स्कोप को सिर्फ़ एक बार लागू किया जा सकता है. header में बदलाव होने पर, Compose अपने किसी भी पैरंट को एक्ज़ीक्यूट किए बिना Column lambda पर जा सकता है. साथ ही, Column को लागू करते समय, Compose LazyColumn के आइटम को छोड़ने का विकल्प चुन सकता है. ऐसा तब होता है, जब names में कोई बदलाव नहीं होता.

साथ ही, सभी कंपोज़ेबल फ़ंक्शन या लैम्डा में साइड इफ़ेक्ट नहीं होना चाहिए. जब आपको कोई साइड-इफ़ेक्ट लागू करना हो, तो उसे कॉलबैक से ट्रिगर करें.

रीकंपोज़िशन ऑप्टिमिस्टिक है

जब भी Compose को लगता है कि कंपोज़ेबल के पैरामीटर बदल गए हैं, तब रिकंपोज़िशन शुरू हो जाता है. रीकंपोज़िशन ऑप्टिमिस्टिक होती है. इसका मतलब है कि Compose को उम्मीद होती है कि पैरामीटर के फिर से बदलने से पहले,रीकंपोज़िशन पूरा हो जाएगा. अगर रीकंपोज़िशन पूरा होने से पहले किसी पैरामीटर में बदलाव होता है, तो Compose रीकंपोज़िशन को रद्द कर सकता है और नए पैरामीटर के साथ इसे फिर से शुरू कर सकता है.

रीकंपोज़िशन रद्द होने पर, Compose, रीकंपोज़िशन से यूज़र इंटरफ़ेस (यूआई) ट्री को खारिज कर देता है. अगर आपको यूज़र इंटरफ़ेस (यूआई) के दिखने पर कोई साइड इफ़ेक्ट मिलता है, तो कंपोज़िशन रद्द होने पर भी साइड इफ़ेक्ट लागू होगा. इससे ऐप्लिकेशन की स्थिति में अंतर आ सकता है.

पुष्टि करें कि सभी कंपोज़ेबल फ़ंक्शन और लैम्डा, आइडमपोटेंट और साइड-इफ़ेक्ट फ़्री हों, ताकि ऑप्टिमिस्टिक रीकंपोज़िशन को हैंडल किया जा सके.

ऐप्लिकेशन बनाने की सुविधा वाले फ़ंक्शन, बहुत बार चल सकते हैं

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

उदाहरण के लिए, अगर आपका विजेट डिवाइस की सेटिंग को पढ़ने की कोशिश करता है, तो वह एक सेकंड में उन सेटिंग को सैकड़ों बार पढ़ सकता है. इससे आपके ऐप्लिकेशन की परफ़ॉर्मेंस पर बुरा असर पड़ सकता है.

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

ऐप्लिकेशन बनाने की सुविधा वाले फ़ंक्शन, एक साथ चल सकते हैं

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

इस ऑप्टिमाइज़ेशन का मतलब है कि कंपोज़ेबल फ़ंक्शन, बैकग्राउंड थ्रेड के पूल में एक्ज़ीक्यूट हो सकता है. अगर कोई कंपोज़ेबल फ़ंक्शन, ViewModel पर किसी फ़ंक्शन को कॉल करता है, तो Compose उस फ़ंक्शन को एक ही समय में कई थ्रेड से कॉल कर सकता है.

यह पुष्टि करने के लिए कि आपका ऐप्लिकेशन सही तरीके से काम कर रहा है, सभी कंपोज़ेबल फ़ंक्शन के कोई साइड इफ़ेक्ट नहीं होने चाहिए. इसके बजाय, साइड इफ़ेक्ट को कॉलबैक से ट्रिगर करें. जैसे, onClick, जो हमेशा यूज़र इंटरफ़ेस (यूआई) थ्रेड पर काम करता है.

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

यहां एक उदाहरण दिया गया है, जिसमें सूची और उसकी संख्या दिखाने वाला कंपोज़ेबल दिखाया गया है:

@Composable
fun ListComposable(myList: List<String>) {
    Row(horizontalArrangement = Arrangement.SpaceBetween) {
        Column {
            for (item in myList) {
                Text("Item: $item")
            }
        }
        Text("Count: ${myList.size}")
    }
}

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

@Composable
fun ListWithBug(myList: List<String>) {
    var items = 0

    Row(horizontalArrangement = Arrangement.SpaceBetween) {
        Column {
            for (item in myList) {
                Card {
                    Text("Item: $item")
                    items++ // Avoid! Side-effect of the column recomposing.
                }
            }
        }
        Text("Count: $items")
    }
}

इस उदाहरण में, हर बार फिर से कंपोज़ करने पर items में बदलाव होता है. यह किसी ऐनिमेशन का हर फ़्रेम या सूची के अपडेट होने पर हो सकता है. दोनों ही मामलों में, यूज़र इंटरफ़ेस (यूआई) पर गलत संख्या दिखेगी. इस वजह से, इस तरह के राइट Compose में काम नहीं करते. इन राइट को ब्लॉक करके, हम फ़्रेमवर्क को थ्रेड बदलने की अनुमति देते हैं, ताकि कंपोज़ेबल लैम्डा को लागू किया जा सके.

ऐप्लिकेशन बनाने की सुविधा वाले फ़ंक्शन किसी भी क्रम में लागू किए जा सकते हैं

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

उदाहरण के लिए, मान लें कि आपके पास टैब लेआउट में तीन स्क्रीन बनाने के लिए, इस तरह का कोड है:

@Composable
fun ButtonRow() {
    MyFancyNavigation {
        StartScreen()
        MiddleScreen()
        EndScreen()
    }
}

StartScreen, MiddleScreen, और EndScreen को कॉल किसी भी क्रम में किए जा सकते हैं. इसका मतलब है कि उदाहरण के लिए, StartScreen() कुछ ग्लोबल वैरिएबल (साइड इफ़ेक्ट) सेट नहीं कर सकता और MiddleScreen() उस बदलाव का फ़ायदा नहीं ले सकता. इसके बजाय, उन सभी फ़ंक्शन में ज़रूरी जानकारी होनी चाहिए.

ज़्यादा जानें

Compose और कंपोज़ेबल फ़ंक्शन के बारे में ज़्यादा जानने के लिए, यहां दिए गए अतिरिक्त संसाधन देखें.

वीडियो