स्किप करने का बेहतर मोड

स्ट्रॉन्ग स्किपिंग, Compose कंपाइलर में उपलब्ध एक मोड है. चालू होने पर, यह कंपाइलर के व्यवहार को दो तरीकों से बदलता है:

स्किप करने का बेहतर मोड चालू करना

Kotlin 2.0.20 में, स्ट्रॉन्ग स्किपिंग मोड डिफ़ॉल्ट रूप से चालू होता है.

2.0.20 से पहले की रिलीज़ में, किसी Gradle मॉड्यूल के लिए स्ट्रॉन्ग स्किपिंग की सुविधा चालू करने के लिए, अपने Gradle कॉन्फ़िगरेशन के composeCompiler ब्लॉक में यह विकल्प शामिल करें:

android { ... }

composeCompiler {
   enableStrongSkippingMode = true
}

स्किप करने की सुविधा को कंपोज़ करना

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

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

स्किप कब करना चाहिए

रीकंपोज़िशन के दौरान किसी कंपोज़ेबल को स्किप करना है या नहीं, यह तय करने के लिए Compose हर पैरामीटर की वैल्यू की तुलना उसकी पिछली वैल्यू से करता है. तुलना का टाइप, पैरामीटर की स्टेबिलिटी पर निर्भर करता है.

  • इंस्टेंस इक्वालिटी (===) का इस्तेमाल करके, अनस्टेबल पैरामीटर की तुलना की जाती है
  • ऑब्जेक्ट इक्वैलिटी (Object.equals()) का इस्तेमाल करके, स्टेबल पैरामीटर की तुलना की जाती है

अगर सभी पैरामीटर इन ज़रूरी शर्तों को पूरा करते हैं, तो Compose, फिर से कॉम्पोज़ करने के दौरान कॉम्पोज़ेबल को स्किप कर देता है.

ऐसा हो सकता है कि आपको किसी कंपोज़ेबल को स्ट्रॉन्ग स्किपिंग मोड से ऑप्ट आउट करना हो. इसका मतलब है कि आपको ऐसा कंपोज़ेबल चाहिए जो रीस्टार्ट हो सके, लेकिन स्किप न किया जा सके. इस मामले में, @NonSkippableComposable ऐनोटेशन का इस्तेमाल करें.

@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}

क्लास को स्टेबल के तौर पर एनोटेट करना

अगर आपको किसी ऑब्जेक्ट की तुलना, इंस्टेंस इक्वैलिटी (===) के बजाय ऑब्जेक्ट इक्वैलिटी (Object.equals()) का इस्तेमाल करके करनी है, तो दी गई क्लास को @Stable या @Immutable के साथ एनोटेट करना जारी रखें.

@Stable या @Immutable जोड़ने से पहले, इन बातों का ध्यान रखें:

  • Compose मॉड्यूल में स्टेबल प्रॉपर्टी वाली क्लास पहले से ही स्टेबल होती हैं: Compose कंपाइलर की मदद से कंपाइल किए गए मॉड्यूल में, स्टेबल टाइप की val प्रॉपर्टी वाली क्लास को अपने-आप स्टेबल माना जाता है. साथ ही, यह @Immutable या @Stable की ज़रूरत के बिना .equals() का इस्तेमाल करती है.
  • सिर्फ़ उन क्लास के बारे में एनोटेट करें जिनकी .equals() जांच करना आसान हो: जब कंपाइलर, स्टेबिलिटी का अनुमान न लगा पाए (जैसे, Compose के अलावा अन्य मॉड्यूल की क्लास) और एक जैसी वैल्यू वाले नए इंस्टेंस अक्सर असाइन किए जाते हों, तो @Stable या @Immutable जोड़ें. हालांकि, ऐसा तब ही करें, जब क्लास की .equals() जांच करना आसान हो.
  • कलेक्शन वाले मॉडल में एनोटेशन जोड़ते समय सावधानी बरतें: कलेक्शन वाले मॉडल में @Stable या @Immutable जोड़ने (या List को ImmutableList से बदलने) पर, Compose हर बार फिर से कॉम्पोज़ करने पर, कलेक्शन के हर एलिमेंट की तुलना .equals() से करता है. लेज़ी लेआउट (LazyColumn, LazyRow, LazyGrid) में इस्तेमाल किए जाने वाले बड़े कलेक्शन या मॉडल के लिए, हर एलिमेंट की तुलना करना, इंस्टेंस इक्वैलिटी (===) का इस्तेमाल करने या सीधे तौर पर फिर से कंपोज़ करने की तुलना में धीमा हो सकता है.

Lambda मेमोइज़ेशन

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

उदाहरण

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

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

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = {
        use(unstableObject)
        use(stableObject)
    }
}

स्ट्रॉन्ग स्किपिंग की सुविधा चालू होने पर, कंपाइलर लैम्ब्डा को remember कॉल में रैप करके मेमोइज़ करता है:

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = remember(unstableObject, stableObject) {
        {
            use(unstableObject)
            use(stableObject)
        }
    }
}

कुंजियां, तुलना करने के लिए उन्हीं नियमों का पालन करती हैं जो ऐप्लिकेशन बनाने की सुविधा के लिए तय किए गए हैं. रनटाइम, इंस्टेंस की समानता का इस्तेमाल करके, अस्थिर कुंजियों की तुलना करता है. यह ऑब्जेक्ट इक्वालिटी का इस्तेमाल करके, स्टेबल कुंजियों की तुलना करता है.

मेमोइज़ेशन और रीकंपोज़िशन

इस ऑप्टिमाइज़ेशन से, कंपोज़ेबल की संख्या काफ़ी बढ़ जाती है. इन्हें रनटाइम, फिर से कंपोज़ करने के दौरान स्किप कर देता है. मेमोइज़ेशन के बिना, रनटाइम के दौरान किसी भी ऐसे कंपोज़ेबल को नया लैम्ब्डा असाइन करने की संभावना ज़्यादा होती है जो फिर से कंपोज़ करने के दौरान लैम्ब्डा पैरामीटर लेता है. इस वजह से, नए lambda में ऐसे पैरामीटर हैं जो आखिरी कंपोज़िशन के बराबर नहीं हैं. इससे रीकंपोज़िशन होता है.

मेमोइज़ेशन से बचें

अगर आपके पास कोई ऐसा लैम्ब्डा है जिसे आपको मेमोइज़ नहीं करना है, तो @DontMemoize एनोटेशन का इस्तेमाल करें.

val lambda = @DontMemoize {
    ...
}

APK का साइज़

कंपाइल किए जाने पर, स्किप किए जा सकने वाले कंपोज़ेबल, स्किप न किए जा सकने वाले कंपोज़ेबल की तुलना में ज़्यादा कोड जनरेट करते हैं. स्ट्रॉन्ग स्किपिंग की सुविधा चालू होने पर, कंपाइलर करीब-करीब सभी कंपोज़ेबल को स्किप किए जा सकने वाले के तौर पर मार्क करता है. साथ ही, सभी लैम्ब्डा को remember{...} में रैप करता है. इस वजह से, स्ट्रॉन्ग स्किपिंग मोड को चालू करने से आपके ऐप्लिकेशन के APK के साइज़ पर बहुत कम असर पड़ता है.

Now In Android में स्ट्रॉन्ग स्किपिंग की सुविधा चालू करने से, APK का साइज़ 4 केबी बढ़ गया. साइज़ में अंतर, मुख्य रूप से इस बात पर निर्भर करता है कि दिए गए ऐप्लिकेशन में पहले से मौजूद, स्किप न किए जा सकने वाले कंपोज़ेबल की संख्या कितनी थी. हालांकि, यह अंतर बहुत कम होना चाहिए.