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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    • एक ही आर्ग्युमेंट के साथ कई बार कॉल किए जाने पर, फ़ंक्शन एक जैसा काम करता है. साथ ही, यह ग्लोबल वैरिएबल या 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 सिर्फ़ उन हिस्सों को फिर से कंपोज़ करता है जिन्हें अपडेट करने की ज़रूरत होती है. इसका मतलब है कि यह यूज़र इंटरफ़ेस (यूआई) ट्री में, इसके ऊपर या नीचे मौजूद किसी भी कंपोज़ेबल को लागू किए बिना, किसी एक बटन के कंपोज़ेबल को फिर से चलाने के लिए स्किप कर सकता है.

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

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

वीडियो