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

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

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

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

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

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

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

एक आसान कॉम्पोज़ेबल फ़ंक्शन

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

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

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

इस फ़ंक्शन के बारे में ध्यान देने वाली कुछ बातें:

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

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

  • यह फ़ंक्शन, यूज़र इंटरफ़ेस (यूआई) में टेक्स्ट दिखाता है. यह Text() composable फ़ंक्शन को कॉल करके ऐसा करता है, जो असल में टेक्स्ट यूआई एलिमेंट बनाता है. कॉम्पोज़ेबल फ़ंक्शन, दूसरे कॉम्पोज़ेबल फ़ंक्शन को कॉल करके यूआई हैरारकी को दिखाते हैं.

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

  • यह फ़ंक्शन तेज़ है, एक ही नतीजा देता है, और इसमें साइड-इफ़ेक्ट नहीं होते.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/**
 * 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 को लागू करते समय, अगर names में कोई बदलाव नहीं होता है, तो हो सकता है कि Compose, LazyColumn के आइटम को स्किप कर दे.

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

फिर से कॉम्पोज़िशन करने की प्रोसेस में, ऑप्टिमिस्टिक एस्टीमेट का इस्तेमाल किया जाता है

जब भी 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 और कॉम्पोज़ेबल फ़ंक्शन के बारे में ज़्यादा जानने के लिए, यहां दिए गए अन्य संसाधन देखें.

वीडियो