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

आम तौर पर, रीकंपोज़िशन तब ट्रिगर होता है, जब State<T>
ऑब्जेक्ट में कोई बदलाव होता है. Compose इन सभी को ट्रैक करता है. साथ ही, कंपोज़िशन में उन सभी कंपोज़ेबल को चलाता है जो उस खास State<T>
को पढ़ते हैं. इसके अलावा, उन सभी कंपोज़ेबल को भी चलाता है जिन्हें स्किप नहीं किया जा सकता.
अगर किसी कंपोज़ेबल को एक से ज़्यादा बार कॉल किया जाता है, तो कंपोज़िशन में कई इंस्टेंस रखे जाते हैं. कंपोज़िशन में हर कॉल का अपना लाइफ़साइकल होता है.
@Composable fun MyComposable() { Column { Text("Hello") Text("World") } }

MyComposable
का प्रतिनिधित्व. अगर किसी कंपोज़ेबल को कई बार कॉल किया जाता है, तो कंपोज़िशन में कई इंस्टेंस रखे जाते हैं. अलग रंग वाला एलिमेंट, अलग इंस्टेंस होने का संकेत देता है.कंपोज़िशन में कंपोज़ेबल की बनावट
कंपोज़िशन में कंपोज़ेबल के इंस्टेंस की पहचान, उसकी कॉल साइट से होती है. Compose कंपाइलर, हर कॉल साइट को अलग-अलग मानता है. एक से ज़्यादा कॉल साइट से कंपोज़ेबल को कॉल करने पर, कंपोज़िशन में कंपोज़ेबल के कई इंस्टेंस बन जाएंगे.
अगर रीकंपोज़िशन के दौरान, कंपोज़ेबल फ़ंक्शन पिछले कंपोज़िशन के मुकाबले अलग-अलग कंपोज़ेबल फ़ंक्शन को कॉल करता है, तो Compose यह पता लगाएगा कि किन कंपोज़ेबल फ़ंक्शन को कॉल किया गया है या नहीं. साथ ही, जिन कंपोज़ेबल फ़ंक्शन को दोनों कंपोज़िशन में कॉल किया गया था उनके लिए, Compose इनपुट में बदलाव न होने पर, उन्हें फिर से कंपोज़ नहीं करेगा.
साइड इफ़ेक्ट को उनके कंपोज़ेबल से जोड़ने के लिए, उनकी पहचान बनाए रखना ज़रूरी है. इससे वे हर बार रीकंपोज़िशन के लिए रीस्टार्ट होने के बजाय, सही तरीके से पूरे हो सकते हैं.
यह उदाहरण देखें:
@Composable fun LoginScreen(showError: Boolean) { if (showError) { LoginError() } LoginInput() // This call site affects where LoginInput is placed in Composition } @Composable fun LoginInput() { /* ... */ } @Composable fun LoginError() { /* ... */ }
ऊपर दिए गए कोड स्निपेट में, LoginScreen
, LoginError
कंपोज़ेबल को शर्त के हिसाब से कॉल करेगा. वहीं, LoginInput
कंपोज़ेबल को हमेशा कॉल करेगा. हर कॉल में, कॉल साइट और सोर्स की यूनीक पोज़िशन होती है. कंपाइलर इसका इस्तेमाल, कॉल की यूनीक पहचान करने के लिए करेगा.

LoginScreen
का प्रज़ेंटेशन. एक ही रंग का मतलब है कि इसे फिर से कंपोज़ नहीं किया गया है.LoginInput
को पहले कॉल किया जाता था, लेकिन अब इसे दूसरे नंबर पर कॉल किया जाता है. हालांकि, LoginInput
इंस्टेंस को फिर से कंपोज़ करने पर भी सुरक्षित रखा जाएगा. इसके अलावा, LoginInput
में ऐसे कोई पैरामीटर नहीं हैं जिनमें रीयूज़ेबिलिटी के दौरान बदलाव हुआ हो. इसलिए, Compose LoginInput
को कॉल नहीं करेगा.
स्मार्ट रीकंपोज़िशन की सुविधा को बेहतर बनाने के लिए अतिरिक्त जानकारी जोड़ना
किसी कंपोज़ेबल को कई बार कॉल करने पर, उसे कंपोज़िशन में भी कई बार जोड़ा जाएगा. जब एक ही कॉल साइट से कंपोज़ेबल को कई बार कॉल किया जाता है, तो Compose के पास उस कंपोज़ेबल को किए गए हर कॉल की यूनीक पहचान करने के लिए कोई जानकारी नहीं होती. इसलिए, इंस्टेंस को अलग-अलग रखने के लिए, कॉल साइट के साथ-साथ एक्ज़ीक्यूशन के क्रम का इस्तेमाल किया जाता है. कभी-कभी, इस तरह के व्यवहार की ज़रूरत होती है. हालांकि, कुछ मामलों में इससे अनचाहा व्यवहार हो सकता है.
@Composable fun MoviesScreen(movies: List<Movie>) { Column { for (movie in movies) { // MovieOverview composables are placed in Composition given its // index position in the for loop MovieOverview(movie) } } }
ऊपर दिए गए उदाहरण में, कंपोज़िशन में इंस्टेंस को अलग रखने के लिए, कंपोज़ कॉल साइट के साथ-साथ एक्ज़ीक्यूशन के क्रम का इस्तेमाल करता है. अगर सूची के आखिरी में कोई नया movie
जोड़ा जाता है, तो कंपोज़, कंपोज़िशन में पहले से मौजूद इंस्टेंस का फिर से इस्तेमाल कर सकता है. ऐसा इसलिए, क्योंकि सूची में उनकी जगह नहीं बदली है. इसलिए, उन इंस्टेंस के लिए movie
इनपुट एक जैसा है.

MoviesScreen
का प्रतिनिधित्व. कंपोज़िशन में मौजूद MovieOverview
कंपोज़ेबल का फिर से इस्तेमाल किया जा सकता है. MovieOverview
में एक ही रंग का मतलब है कि कंपोज़ेबल को फिर से कंपोज़ नहीं किया गया है.हालांकि, अगर movies
सूची में बदलाव होता है, जैसे कि सूची के ऊपर या बीच में आइटम जोड़ना, आइटम हटाना या उनकी क्रम बदलना, तो इससे उन सभी MovieOverview
कॉल में फिर से कंपोज़िशन होगी जिनके इनपुट पैरामीटर की सूची में बदलाव हुआ है. यह तब बहुत ज़रूरी होता है, जब उदाहरण के लिए, MovieOverview
साइड इफ़ेक्ट का इस्तेमाल करके किसी फ़िल्म की इमेज फ़ेच करता है. अगर इफ़ेक्ट लागू होने के दौरान रीकंपोज़िशन होता है, तो इसे रद्द कर दिया जाएगा और यह फिर से शुरू होगा.
@Composable fun MovieOverview(movie: Movie) { Column { // Side effect explained later in the docs. If MovieOverview // recomposes, while fetching the image is in progress, // it is cancelled and restarted. val image = loadNetworkImage(movie.url) MovieHeader(image) /* ... */ } }

MoviesScreen
का प्रतिनिधित्व. MovieOverview
कंपोज़ेबल का फिर से इस्तेमाल नहीं किया जा सकता. साथ ही, सभी साइड इफ़ेक्ट फिर से शुरू हो जाएंगे. MovieOverview
में अलग रंग का मतलब है कि कंपोज़ेबल को फिर से कंपोज़ किया गया है.हमारा सुझाव है कि MovieOverview
इंस्टेंस की पहचान को movie
की पहचान से लिंक किया जाए. अगर हमें फ़िल्मों की सूची का क्रम बदलना है, तो हम हर MovieOverview
कंपोज़ेबल को किसी दूसरे फ़िल्म इंस्टेंस के साथ फिर से कंपोज़ करने के बजाय, कंपोज़िशन ट्री में इंस्टेंस का क्रम बदल देंगे. Compose, रनटाइम को यह बताने का तरीका उपलब्ध कराता है कि आपको ट्री के किसी हिस्से की पहचान करने के लिए किन वैल्यू का इस्तेमाल करना है: key
कंपोज़ेबल.
कोड के किसी ब्लॉक को, एक या उससे ज़्यादा वैल्यू के साथ पास की गई कंपोज़ेबल की के कॉल के साथ रैप करने पर, उन वैल्यू को कंपोज़िशन में उस इंस्टेंस की पहचान करने के लिए इस्तेमाल किया जाएगा. key
की वैल्यू का ग्लोबल स्तर पर यूनीक होना ज़रूरी नहीं है. यह सिर्फ़ कॉल साइट पर कंपोज़ेबल के इनवोकेशन के बीच यूनीक होनी चाहिए. इसलिए, इस उदाहरण में हर movie
के पास एक key
होना चाहिए, जो movies
में यूनीक हो. अगर यह key
को ऐप्लिकेशन में कहीं और मौजूद किसी अन्य कंपोज़ेबल के साथ शेयर करता है, तो इसमें कोई समस्या नहीं है.
@Composable fun MoviesScreenWithKey(movies: List<Movie>) { Column { for (movie in movies) { key(movie.id) { // Unique ID for this movie MovieOverview(movie) } } } }
ऊपर दी गई जानकारी के हिसाब से, सूची में मौजूद एलिमेंट में बदलाव होने पर भी, कंपोज़ करने की सुविधा MovieOverview
को अलग-अलग कॉल को पहचान सकती है और उनका फिर से इस्तेमाल कर सकती है.

MoviesScreen
का प्रतिनिधित्व. MovieOverview
कंपोज़ेबल के पास यूनीक कुंजियां होती हैं. इसलिए, Compose यह पहचान लेता है कि MovieOverview
के किन इंस्टेंस में बदलाव नहीं हुआ है और उनका फिर से इस्तेमाल कर सकता है. इनके साइड इफ़ेक्ट काम करते रहेंगे.कुछ कंपोज़ेबल में, key
कंपोज़ेबल के लिए पहले से ही सहायता मौजूद होती है. उदाहरण के लिए,
LazyColumn
, items
डीएसएल में कस्टम key
तय करने की सुविधा देता है.
@Composable fun MoviesScreenLazy(movies: List<Movie>) { LazyColumn { items(movies, key = { movie -> movie.id }) { movie -> MovieOverview(movie) } } }
अगर इनपुट में कोई बदलाव नहीं हुआ है, तो इस चरण को छोड़ दिया जाता है
रीकंपोज़िशन के दौरान, कुछ कंपोज़ेबल फ़ंक्शन के एक्ज़ीक्यूशन को पूरी तरह से स्किप किया जा सकता है. ऐसा तब होता है, जब उनके इनपुट में पिछले कंपोज़िशन से कोई बदलाव नहीं हुआ हो.
किसी कंपोज़ेबल फ़ंक्शन को तब तक स्किप किया जा सकता है, जब तक:
- फ़ंक्शन का रिटर्न टाइप,
Unit
नहीं है - फ़ंक्शन को
@NonRestartableComposable
या@NonSkippableComposable
के साथ एनोटेट किया गया है - ज़रूरी पैरामीटर, स्टेबल टाइप का नहीं है
कंपाइलर का एक एक्सपेरिमेंटल मोड है, स्ट्रॉन्ग स्किपिंग. यह आखिरी ज़रूरी शर्त को आसान बना देता है.
किसी टाइप को स्टेबल माना जाने के लिए, यह ज़रूरी है कि वह इस समझौते का पालन करे:
- दो इंस्टेंस के लिए
equals
का नतीजा, उन दो इंस्टेंस के लिए हमेशा एक जैसा रहेगा. - अगर किसी सार्वजनिक प्रॉपर्टी का टाइप बदलता है, तो Composition को इसकी सूचना दी जाएगी.
- सभी सार्वजनिक प्रॉपर्टी टाइप भी स्टेबल हैं.
इस कानूनी समझौते के तहत, कुछ सामान्य टाइप आते हैं. Compose कंपाइलर इन्हें स्टेबल के तौर पर ट्रीट करेगा. भले ही, इन्हें @Stable
एनोटेशन का इस्तेमाल करके, साफ़ तौर पर स्टेबल के तौर पर मार्क न किया गया हो:
- सभी प्रिमिटिव वैल्यू टाइप:
Boolean
,Int
,Long
,Float
,Char
वगैरह. - स्ट्रिंग
- सभी फ़ंक्शन टाइप (लैम्डा)
ये सभी टाइप, स्टेबल के अनुबंध का पालन कर सकते हैं, क्योंकि ये अपरिवर्तनीय हैं. इम्यूटेबल टाइप कभी नहीं बदलते. इसलिए, उन्हें बदलाव की जानकारी देने की ज़रूरत नहीं होती. इसलिए, इस कानूनी समझौते का पालन करना बहुत आसान होता है.
एक अहम टाइप, Compose का MutableState
टाइप है. यह स्टेबल है, लेकिन इसमें बदलाव किया जा सकता है. अगर कोई वैल्यू MutableState
में सेव की जाती है, तो पूरे स्टेट ऑब्जेक्ट को स्थिर माना जाता है. ऐसा इसलिए, क्योंकि Compose को State
की .value
प्रॉपर्टी में होने वाले किसी भी बदलाव की सूचना मिल जाएगी.
जब कंपोज़ेबल में पैरामीटर के तौर पर पास किए गए सभी टाइप स्थिर होते हैं, तब यूज़र इंटरफ़ेस (यूआई) ट्री में कंपोज़ेबल की पोज़िशन के आधार पर, पैरामीटर वैल्यू की तुलना की जाती है. अगर पिछली कॉल के बाद से सभी वैल्यू में कोई बदलाव नहीं हुआ है, तो रीकंपोज़िशन को स्किप कर दिया जाता है.
Compose किसी टाइप को सिर्फ़ तब स्टेबल मानता है, जब वह इसे साबित कर सकता है. उदाहरण के लिए, किसी इंटरफ़ेस को आम तौर पर स्टेबल नहीं माना जाता. साथ ही, ऐसी सार्वजनिक प्रॉपर्टी वाले टाइप भी स्टेबल नहीं होते हैं जिनमें बदलाव किया जा सकता है. हालांकि, उनके लागू करने के तरीके में बदलाव नहीं किया जा सकता.
अगर Compose यह पता नहीं लगा पाता है कि कोई टाइप स्टेबल है, लेकिन आपको Compose को इसे स्टेबल के तौर पर इस्तेमाल करने के लिए मजबूर करना है, तो इसे @Stable
एनोटेशन के साथ मार्क करें.
// Marking the type as stable to favor skipping and smart recompositions. @Stable interface UiState<T : Result<T>> { val value: T? val exception: Throwable? val hasError: Boolean get() = exception != null }
ऊपर दिए गए कोड स्निपेट में, UiState
एक इंटरफ़ेस है. इसलिए, Compose इस टाइप को आम तौर पर स्टेबल नहीं मानता. @Stable
एनोटेशन जोड़ने से, Compose को यह पता चलता है कि यह टाइप स्टेबल है. इससे Compose को स्मार्ट रीकंपोज़िशन को प्राथमिकता देने में मदद मिलती है. इसका यह भी मतलब है कि अगर इंटरफ़ेस का इस्तेमाल पैरामीटर टाइप के तौर पर किया जाता है, तो Compose अपने सभी लागू करने के तरीकों को स्थिर मानेगा.
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक टेक्स्ट दिखता है
- स्टेट और Jetpack Compose
- लिखने में मदद करने वाली सुविधा के बुरे असर
- Compose में यूज़र इंटरफ़ेस (यूआई) की स्थिति सेव करना