अगर परफ़ॉर्मेंस से जुड़ी समस्याओं की वजह से अनिश्चित क्लास का सामना करना पड़ रहा है, तो आपको इसे स्थिर बनाना चाहिए. इस दस्तावेज़ में, ऐसा करने के लिए कई तकनीकों के बारे में बताया गया है.
वीडियो को तेज़ी से स्किप करने की सुविधा चालू करना
सबसे पहले, आपको गाने के बीच में ज़्यादा से ज़्यादा समय तक स्किप करने की सुविधा चालू करनी चाहिए. स्ट्रॉन्ग स्किपिंग मोड, अस्थिर पैरामीटर वाले कंपोज़ेबल को स्किप करने की अनुमति देता है. यह स्थिरता की वजह से परफ़ॉर्मेंस से जुड़ी समस्याओं को ठीक करने का सबसे आसान तरीका है.
ज़्यादा जानकारी के लिए, वीडियो को बहुत ज़्यादा स्किप करना लेख पढ़ें.
क्लास को नहीं बदले जा सकने वाला बनाएं
आप एक अस्थिर क्लास को पूरी तरह से नहीं बदले जाने लायक बनाने की कोशिश भी कर सकते हैं.
- Immutable: इस एट्रिब्यूट का इस्तेमाल ऐसे टाइप के लिए किया जाता है जिसका कोई इंस्टेंस बनने के बाद, किसी भी प्रॉपर्टी की वैल्यू कभी नहीं बदल सकती. साथ ही, सभी तरीके, रेफ़रंस के हिसाब से पारदर्शी होते हैं.
- पक्का करें कि क्लास की सभी प्रॉपर्टी,
var
के बजायval
हों और वे बदलाव न किए जा सकने वाले टाइप की हों. String, Int
औरFloat
जैसे प्रिमिटिव टाइप हमेशा नहीं बदले जा सकते.- अगर ऐसा नहीं किया जा सकता, तो आपको बदली जा सकने वाली किसी भी प्रॉपर्टी के लिए, Compose स्टेट का इस्तेमाल करना होगा.
- पक्का करें कि क्लास की सभी प्रॉपर्टी,
- स्टेबल: यह ऐसे टाइप के बारे में बताता है जिसमें बदलाव किया जा सकता है. Compose के रनटाइम को यह पता नहीं चलता कि क्या किसी टाइप की सार्वजनिक प्रॉपर्टी या तरीके की वजह से, पिछली बार ट्रिगर किए जाने से अलग नतीजे मिलेंगे.
इम्यूटेबल कलेक्शन
Compose में क्लास को हिलने-डुलने की एक आम वजह, कलेक्शन है. जैसा कि स्थिरता से जुड़ी समस्याओं का पता लगाएं पेज पर बताया गया है, Compose कंपाइलर इस बात पर पूरी तरह से यकीन नहीं कर सकता कि List, Map
और Set
जैसे कलेक्शन में कोई बदलाव नहीं किया जा सकता. इसलिए, उन्हें स्टेबल के तौर पर मार्क किया जाता है.
इसे ठीक करने के लिए, ऐसे कलेक्शन इस्तेमाल किए जा सकते हैं जिन्हें बदला नहीं जा सकता. Compose कंपाइलर Kotlinx के इंम्यूटेबल कलेक्शन के साथ काम करता है. इन कलेक्शन में बदलाव नहीं किया जा सकता. Compose कंपाइलर भी इनके साथ इसी तरह पेश आता है. यह लाइब्रेरी अब भी अल्फा वर्शन में है. इसलिए, इसके एपीआई में बदलाव हो सकते हैं.
स्थिरता से जुड़ी समस्याओं का पता लगाएं गाइड की मदद से, इस अस्थिर क्लास के बारे में फिर से सोचें:
unstable class Snack {
…
unstable val tags: Set<String>
…
}
बदलाव न किए जा सकने वाले कलेक्शन का इस्तेमाल करके, tags
को स्थिर किया जा सकता है. क्लास में, tags
के टाइप को बदलकर ImmutableSet<String>
करें:
data class Snack{
…
val tags: ImmutableSet<String> = persistentSetOf()
…
}
ऐसा करने के बाद, क्लास के सभी पैरामीटर में बदलाव नहीं किया जा सकता. साथ ही, Compose कंपाइलर क्लास को स्थिर के तौर पर मार्क करता है.
Stable
या Immutable
का इस्तेमाल करके एनोटेट करना
अस्थिर क्लास को @Stable
या @Immutable
के साथ एनोटेट करके, ऐप्लिकेशन के हैंग या क्रैश होने से जुड़ी समस्याओं को हल किया जा सकता है.
किसी क्लास में एनोटेशन जोड़ने का मतलब है कि आपने क्लास के बारे में, कंपाइलर के अनुमान को बदल दिया है. यह !!
Kotlin की ऑपरेटर के जैसा है. आपको इन एनोटेशन का इस्तेमाल करते समय बहुत सावधान रहना चाहिए. कंपाइलर के व्यवहार में बदलाव करने से, आपको अचानक से कुछ गड़बड़ियां मिल सकती हैं. जैसे, आपके कंपोज़ेबल को फिर से कंपोज़ नहीं किया जा सकता.
अगर किसी एनोटेशन के बिना आपकी क्लास को स्थिर बनाया जा सकता है, तो आपको इस तरह से स्थिरता पाने की कोशिश करनी चाहिए.
नीचे दिया गया स्निपेट, ऐसी डेटा क्लास का एक छोटा उदाहरण देता है जिसे 'बदलाव नहीं किया जा सकता' के तौर पर एनोटेट किया गया है:
@Immutable
data class Snack(
…
)
चाहे आप @Immutable
एनोटेशन का इस्तेमाल करें या @Stable
एनोटेशन का, Compose कंपाइलर Snack
क्लास को स्टेबल के तौर पर मार्क करता है.
कलेक्शन में एनोटेट की गई क्लास
List<Snack>
टाइप का पैरामीटर शामिल करने वाले कॉम्पोज़ेबल पर विचार करें:
restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
…
unstable snacks: List<Snack>
…
)
भले ही, आपने Snack
को @Immutable
के साथ एनोटेट किया हो, फिर भी Compose कंपाइलर, HighlightedSnacks
में snacks
पैरामीटर को अस्थिर के तौर पर मार्क करता है.
कलेक्शन टाइप के मामले में पैरामीटर में भी वही समस्या आती है जो क्लास में होती है. कंपोज़ कंपाइलर, List
टाइप के पैरामीटर को हमेशा 'स्टेबल' के तौर पर मार्क करता है. ऐसा तब भी होता है, जब वह स्थायी टाइप का कलेक्शन हो.
किसी एक पैरामीटर को स्टेबल के तौर पर मार्क नहीं किया जा सकता और न ही किसी कंपोज़ेबल के एनोटेशन को 'हमेशा स्किप किया जा सकने वाला' के तौर पर मार्क किया जा सकता है. आगे कई रास्ते हैं.
कलेक्शन में बदलाव न होने से जुड़ी समस्या को हल करने के कई तरीके हैं. इन सब-सेक्शन में, इन अलग-अलग तरीकों के बारे में बताया गया है.
कॉन्फ़िगरेशन फ़ाइल
अगर आपको अपने कोडबेस में स्थिरता के अनुबंध का पालन करना है, तो आपके पास Kotlin कलेक्शन को स्टेबल के तौर पर स्वीकार करने का विकल्प है. इसके लिए, आपको स्टेबिलिटी कॉन्फ़िगरेशन फ़ाइल में kotlin.collections.*
जोड़ना होगा.
इम्यूटेबल कलेक्शन
कॉम्पाइल के समय, डेटा में बदलाव न होने की सुरक्षा के लिए, List
के बजाय kotlinx के immutable collection का इस्तेमाल किया जा सकता है.
@Composable
private fun HighlightedSnacks(
…
snacks: ImmutableList<Snack>,
…
)
Wrapper
अगर ऐसे कलेक्शन का इस्तेमाल नहीं किया जा सकता जिसमें बदलाव नहीं किया जा सकता, तो अपना कलेक्शन बनाया जा सकता है. ऐसा करने के लिए,
List
को एनोटेट की गई स्टैबल क्लास में रैप करें. आपकी ज़रूरतों के हिसाब से, जेनरिक रैपर सबसे अच्छा विकल्प हो सकता है.
@Immutable
data class SnackCollection(
val snacks: List<Snack>
)
इसके बाद, इसे अपने कंपोज़ेबल में पैरामीटर के टाइप के तौर पर इस्तेमाल किया जा सकता है.
@Composable
private fun HighlightedSnacks(
index: Int,
snacks: SnackCollection,
onSnackClick: (Long) -> Unit,
modifier: Modifier = Modifier
)
समाधान
इनमें से किसी भी तरीके को अपनाने के बाद, Compose कंपाइलर अब
HighlightedSnacks
कंपोज़ेबल को skippable
और restartable
, दोनों के तौर पर मार्क करता है.
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
stable index: Int
stable snacks: ImmutableList<Snack>
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
)
अगर कंपोज़िशन के किसी भी इनपुट में कोई बदलाव नहीं किया गया है, तो बदलाव के दौरान 'लिखें' विंडो अब HighlightedSnacks
को स्किप कर सकता है.
स्टेबिलिटी कॉन्फ़िगरेशन फ़ाइल
Compose Compiler 1.5.5 से, कंपाइल करने के समय उन क्लास की कॉन्फ़िगरेशन फ़ाइल दी जा सकती है जिन्हें स्थिर माना जाता है. इससे उन क्लास को स्थिर माना जा सकता है जिन पर आपका कंट्रोल नहीं होता. जैसे, LocalDateTime
जैसी स्टैंडर्ड लाइब्रेरी क्लास.
कॉन्फ़िगरेशन फ़ाइल एक सादा टेक्स्ट फ़ाइल है, जिसमें हर पंक्ति में एक क्लास होती है. टिप्पणियां, सिंगल, और डबल वाइल्डकार्ड इस्तेमाल किए जा सकते हैं. कॉन्फ़िगरेशन का उदाहरण:
// Consider LocalDateTime stable
java.time.LocalDateTime
// Consider my datalayer stable
com.datalayer.*
// Consider my datalayer and all submodules stable
com.datalayer.**
// Consider my generic type stable based off it's first type parameter only
com.example.GenericClass<*,_>
इस सुविधा को चालू करने के लिए, कॉन्फ़िगरेशन फ़ाइल के पाथ को Compose कंपाइलर Gradle प्लग इन कॉन्फ़िगरेशन के composeCompiler
विकल्प ब्लॉक में पास करें.
composeCompiler {
stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_config.conf")
}
Compose कंपाइलर आपके प्रोजेक्ट के हर मॉड्यूल पर अलग-अलग काम करता है. इसलिए, ज़रूरत पड़ने पर अलग-अलग मॉड्यूल के लिए अलग-अलग कॉन्फ़िगरेशन दिए जा सकते हैं. इसके अलावा, अपने प्रोजेक्ट के रूट लेवल पर एक कॉन्फ़िगरेशन रखें और उस पाथ को हर मॉड्यूल पर पास करें.
एक से ज़्यादा मॉड्यूल
एक और सामान्य समस्या, मल्टी-मॉड्यूल आर्किटेक्चर से जुड़ी है. Compose कंपाइलर, किसी क्लास के स्टेबल होने का अनुमान सिर्फ़ तब लगा सकता है, जब उसमें रेफ़र किए गए सभी नॉन-प्राइमटिव टाइप, साफ़ तौर पर स्टेबल के तौर पर मार्क किए गए हों या किसी ऐसे मॉड्यूल में हों जिसे Compose कंपाइलर से भी बनाया गया हो.
अगर आपकी डेटा लेयर, यूज़र इंटरफ़ेस (यूआई) लेयर से अलग मॉड्यूल में है, तो आपको यह समस्या आ सकती है. हालांकि, ऐसा करने का सुझाव नहीं दिया जाता.
समाधान
इस समस्या को हल करने के लिए, इनमें से कोई एक तरीका आज़माया जा सकता है:
- अपनी कंपाइलर कॉन्फ़िगरेशन फ़ाइल में क्लास जोड़ें.
- अपने डेटा लेयर मॉड्यूल पर, Compose कंपाइलर चालू करें या जहां भी ज़रूरी हो वहां अपनी क्लास को
@Stable
या@Immutable
से टैग करें.- इसमें, आपके डेटा लेयर में Compose डिपेंडेंसी जोड़ना शामिल है. हालांकि, यह सिर्फ़ कंपोज़ रनटाइम के लिए डिपेंडेंसी है, न कि
Compose-UI
के लिए.
- इसमें, आपके डेटा लेयर में Compose डिपेंडेंसी जोड़ना शामिल है. हालांकि, यह सिर्फ़ कंपोज़ रनटाइम के लिए डिपेंडेंसी है, न कि
- अपने यूज़र इंटरफ़ेस (यूआई) मॉड्यूल में, अपनी डेटा लेयर क्लास को यूआई के हिसाब से बनाई गई रैपर क्लास में रैप करें.
बाहरी लाइब्रेरी का इस्तेमाल करने पर भी यही समस्या होती है. हालांकि, ऐसा तब होता है, जब वे Compose कंपाइलर का इस्तेमाल न करती हों.
हर कॉम्पोज़ेबल को स्किप नहीं किया जा सकता
स्थिरता से जुड़ी समस्याओं को ठीक करते समय, आपको हर बार स्किप किए जा सकने वाले सभी कंपोज़ेबल बनाने की कोशिश नहीं करनी चाहिए. ऐसा करने से समय से पहले ऑप्टिमाइज़ेशन हो सकता है. इसमें समस्याएं होती हैं, जो ठीक करने से ज़्यादा होती हैं.
कई मामलों में, स्किप किए जा सकने की सुविधा का कोई फ़ायदा नहीं होता. साथ ही, इससे कोड को मैनेज करना मुश्किल हो सकता है. उदाहरण के लिए:
- ऐसा कॉम्पोज़ेबल जिसे बार-बार या कभी भी फिर से कॉम्पोज़ नहीं किया जाता.
- एक ऐसा कंपोज़ेबल जो अपने-आप में सिर्फ़ स्किप किए जा सकने वाले कंपोज़ेबल को कॉल करता है.
- कई पैरामीटर वाला एक कंपोज़ेबल जिसमें महंगे बराबर फ़ंक्शन लागू किए गए हों. इस मामले में, यह पता लगाने की लागत कि किसी पैरामीटर में बदलाव हुआ है या नहीं, यह पता लगाने की लागत, सस्ते में दोबारा बनाने की लागत से ज़्यादा हो सकती है.
जब किसी कंपोज़ेबल को स्किप किया जा सकता है, तब यह एक छोटा ओवरहेड जोड़ देता है. हो सकता है कि यह काम का न हो. अगर आपको लगता है कि फिर से शुरू नहीं किया जा सकने वाले कॉम्पोज़ेबल का इस्तेमाल करना ज़्यादा बेहतर है, तो अपने कॉम्पोज़ेबल के लिए एनोटेट किया जा सकता है.