स्थिति और Jetpack Compose

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

सभी Android ऐप्लिकेशन, उपयोगकर्ता को स्थिति दिखाते हैं. Android ऐप्लिकेशन में स्थिति के कुछ उदाहरण:

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

Jetpack Compose की मदद से, Android ऐप्लिकेशन में स्टेट को स्टोर करने और इस्तेमाल करने के तरीके के बारे में साफ़ तौर पर बताया जा सकता है. इस गाइड में, स्टेट और कंपोज़ेबल के बीच कनेक्शन के बारे में बताया गया है. साथ ही, उन एपीआई के बारे में बताया गया है जो Jetpack Compose, स्टेट के साथ आसानी से काम करने के लिए उपलब्ध कराता है.

स्थिति और कंपोज़िशन

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

@Composable
private fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello!",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(
            value = "",
            onValueChange = { },
            label = { Text("Name") }
        )
    }
}

इसे चलाने और टेक्स्ट डालने पर, आपको दिखेगा कि कुछ नहीं हो रहा है. ऐसा इसलिए है, क्योंकि TextField अपने-आप अपडेट नहीं होता. यह तब अपडेट होता है, जब इसका value पैरामीटर बदलता है. ऐसा इसलिए होता है, क्योंकि Compose में कंपोज़िशन और रीकंपोज़िशन इसी तरह काम करते हैं.

शुरुआती कंपोज़िशन और रीकंपोज़िशन के बारे में ज़्यादा जानने के लिए, Compose के बारे में सोचना लेख पढ़ें.

कंपोज़ेबल में स्टेट

कंपोज़ेबल फ़ंक्शन, मेमोरी में किसी ऑब्जेक्ट को सेव करने के लिए remember एपीआई का इस्तेमाल कर सकते हैं. remember से कैलकुलेट की गई वैल्यू, शुरुआती कंपोज़िशन के दौरान कंपोज़िशन में सेव की जाती है. इसके बाद, रीकंपोज़िशन के दौरान सेव की गई वैल्यू को दिखाया जाता है. remember का इस्तेमाल, बदले जा सकने वाले और नहीं बदले जा सकने वाले, दोनों तरह के ऑब्जेक्ट को सेव करने के लिए किया जा सकता है.

mutableStateOf एक ऑब्ज़र्वेबल MutableState<T> बनाता है. यह एक ऑब्ज़र्वेबल टाइप है, जिसे कंपोज़ रनटाइम के साथ इंटिग्रेट किया जाता है.

interface MutableState<T> : State<T> {
    override var value: T
}

value में किए गए किसी भी बदलाव से, value को पढ़ने वाले किसी भी कंपोज़ेबल फ़ंक्शन के शेड्यूल को फिर से कंपोज़ किया जाएगा.

कंपोज़ेबल में MutableState ऑब्जेक्ट को तीन तरीकों से एलान किया जा सकता है:

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

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

by डेलिगेट सिंटैक्स के लिए, यहां दिए गए इंपोर्ट की ज़रूरत होती है:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

याद रखी गई वैल्यू का इस्तेमाल, अन्य कंपोज़ेबल के लिए पैरामीटर के तौर पर किया जा सकता है. इसके अलावा, इसका इस्तेमाल स्टेटमेंट में लॉजिक के तौर पर भी किया जा सकता है, ताकि यह बदला जा सके कि कौनसे कंपोज़ेबल दिखाए जाएं. उदाहरण के लिए, अगर नाम खाली होने पर आपको बधाई नहीं दिखानी है, तो if स्टेटमेंट में स्थिति का इस्तेमाल करें:

@Composable
fun HelloContent() {
    Column(modifier = Modifier.padding(16.dp)) {
        var name by remember { mutableStateOf("") }
        if (name.isNotEmpty()) {
            Text(
                text = "Hello, $name!",
                modifier = Modifier.padding(bottom = 8.dp),
                style = MaterialTheme.typography.bodyMedium
            )
        }
        OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("Name") }
        )
    }
}

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

स्टेट के अन्य टाइप, जिनके साथ काम किया जा सकता है

Compose में, MutableState<T> का इस्तेमाल करके स्टेट को होल्ड करने की ज़रूरत नहीं होती. यह अन्य ऑब्ज़र्वेबल टाइप के साथ काम करता है. Compose में किसी अन्य ऑब्ज़र्वेबल टाइप को पढ़ने से पहले, आपको उसे State<T> में बदलना होगा, ताकि स्टेट में बदलाव होने पर कंपोज़ेबल अपने-आप फिर से कंपोज़ हो सकें.

Compose में, Android ऐप्लिकेशन में इस्तेमाल होने वाले सामान्य ऑब्ज़र्वेबल टाइप से State<T> बनाने के लिए फ़ंक्शन शामिल होते हैं. इन इंटिग्रेशन का इस्तेमाल करने से पहले, नीचे बताए गए तरीके से सही आर्टफ़ैक्ट जोड़ें:

  • Flow: collectAsStateWithLifecycle()

    collectAsStateWithLifecycle(), लाइफ़साइकल के हिसाब से Flow से वैल्यू इकट्ठा करता है. इससे आपका ऐप्लिकेशन, ऐप्लिकेशन के संसाधनों को बचा पाता है. यह Compose State से हाल ही में जारी की गई वैल्यू को दिखाता है. Android ऐप्लिकेशन पर फ़्लो इकट्ठा करने के लिए, इस एपीआई का इस्तेमाल करें.

    build.gradle फ़ाइल में यह डिपेंडेंसी होना ज़रूरी है. यह 2.6.0-beta01 या इससे नया वर्शन होना चाहिए:

Kotlin

dependencies {
      ...
      implementation("androidx.lifecycle:lifecycle-runtime-compose:2.10.0")
}

शानदार

dependencies {
      ...
      implementation "androidx.lifecycle:lifecycle-runtime-compose:2.10.0"
}
  • Flow: collectAsState()

    collectAsState, collectAsStateWithLifecycle के जैसा ही है, क्योंकि यह भी Flow से वैल्यू इकट्ठा करता है और उन्हें Compose State में बदलता है.

    सिर्फ़ Android के लिए उपलब्ध collectAsStateWithLifecycle के बजाय, प्लैटफ़ॉर्म से अलग कोड के लिए collectAsState का इस्तेमाल करें.

    collectAsState के लिए, किसी अन्य डिपेंडेंसी की ज़रूरत नहीं होती, क्योंकि यह compose-runtime में उपलब्ध है.

  • LiveData: observeAsState()

    observeAsState() इस LiveData को मॉनिटर करना शुरू करता है और इसकी वैल्यू को State के ज़रिए दिखाता है.

    build.gradle फ़ाइल में, यह डिपेंडेंसी ज़रूरी है:

Kotlin

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-livedata:1.11.1")
}

शानदार

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-livedata:1.11.1"
}

Kotlin

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava2:1.11.1")
}

शानदार

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava2:1.11.1"
}

Kotlin

dependencies {
      ...
      implementation("androidx.compose.runtime:runtime-rxjava3:1.11.1")
}

शानदार

dependencies {
      ...
      implementation "androidx.compose.runtime:runtime-rxjava3:1.11.1"
}

स्टेटफ़ुल बनाम स्टेटलेस

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

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

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

स्टेट होइस्टिंग

Compose में स्टेट होइस्टिंग एक ऐसा पैटर्न है जिसमें स्टेट को कंपोज़ेबल के कॉलर में ले जाया जाता है, ताकि कंपोज़ेबल को स्टेटलेस बनाया जा सके. Jetpack Compose में, स्टेट को ऊपर ले जाने का सामान्य पैटर्न यह है कि स्टेट वैरिएबल को दो पैरामीटर से बदल दिया जाए:

  • value: T: दिखाने के लिए मौजूदा वैल्यू
  • onValueChange: (T) -> Unit: ऐसा इवेंट जिसमें वैल्यू बदलने का अनुरोध किया गया हो, जहां T सुझाई गई नई वैल्यू है

हालांकि, आपको सिर्फ़ onValueChange का इस्तेमाल करने की ज़रूरत नहीं है. अगर कंपोज़ेबल के लिए ज़्यादा खास इवेंट सही हैं, तो आपको उन्हें लैम्डा का इस्तेमाल करके तय करना चाहिए.

इस तरह से होस्ट किए गए स्टेट की कुछ अहम प्रॉपर्टी होती हैं:

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

उदाहरण के तौर पर दिए गए मामले में, HelloContent से name और onValueChange को निकाला जाता है. इसके बाद, उन्हें ट्री में ऊपर की ओर ले जाकर, HelloScreen कंपोज़ेबल में रखा जाता है. यह कंपोज़ेबल, HelloContent को कॉल करता है.

@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }

    HelloContent(name = name, onNameChange = { name = it })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.bodyMedium
        )
        OutlinedTextField(value = name, onValueChange = onNameChange, label = { Text("Name") })
    }
}

स्टेट को HelloContent से बाहर ले जाने पर, कंपोज़ेबल के बारे में तर्क देना, अलग-अलग स्थितियों में इसका फिर से इस्तेमाल करना, और इसे टेस्ट करना आसान हो जाता है. HelloContent को इस बात से अलग कर दिया जाता है कि उसके स्टेटस को कैसे सेव किया जाता है. डिकपल करने का मतलब है कि अगर आपको HelloScreen में बदलाव करना है या इसे बदलना है, तो आपको HelloContent को लागू करने के तरीके में बदलाव करने की ज़रूरत नहीं है.

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

ज़्यादा जानने के लिए, स्टेट को कहां होस्ट करें पेज देखें.

Compose में स्टेट को वापस लाना

rememberSaveable एपीआई, remember की तरह ही काम करता है. ऐसा इसलिए, क्योंकि यह रेंडरिंग के दौरान स्थिति को बनाए रखता है. साथ ही, सेव किए गए इंस्टेंस की स्थिति के मैकेनिज़्म का इस्तेमाल करके, गतिविधि या प्रोसेस को फिर से बनाने के दौरान भी स्थिति को बनाए रखता है. उदाहरण के लिए, ऐसा तब होता है, जब स्क्रीन को घुमाया जाता है.

स्टेट को सेव करने के तरीके

Bundle में जोड़े गए सभी डेटा टाइप अपने-आप सेव हो जाते हैं. अगर आपको कोई ऐसी चीज़ सेव करनी है जिसे Bundle में नहीं जोड़ा जा सकता, तो आपके पास कई विकल्प हैं.

पार्सलाइज़

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

@Parcelize
data class City(val name: String, val country: String) : Parcelable

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

MapSaver

अगर किसी वजह से @Parcelize का इस्तेमाल नहीं किया जा सकता, तो mapSaver का इस्तेमाल करके, किसी ऑब्जेक्ट को वैल्यू के ऐसे सेट में बदला जा सकता है जिसे सिस्टम Bundle में सेव कर सकता है.

data class City(val name: String, val country: String)

val CitySaver = run {
    val nameKey = "Name"
    val countryKey = "Country"
    mapSaver(
        save = { mapOf(nameKey to it.name, countryKey to it.country) },
        restore = { City(it[nameKey] as String, it[countryKey] as String) }
    )
}

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

ListSaver

मैप के लिए कुंजियां तय करने की ज़रूरत से बचने के लिए, listSaver का इस्तेमाल किया जा सकता है. साथ ही, इसके इंडेक्स को कुंजियों के तौर पर इस्तेमाल किया जा सकता है:

data class City(val name: String, val country: String)

val CitySaver = listSaver<City, Any>(
    save = { listOf(it.name, it.country) },
    restore = { City(it[0] as String, it[1] as String) }
)

@Composable
fun CityScreen() {
    var selectedCity = rememberSaveable(stateSaver = CitySaver) {
        mutableStateOf(City("Madrid", "Spain"))
    }
}

Compose में स्टेट होल्डर

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

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

कुंजियां बदलने पर, याद रखने से जुड़ी कैलकुलेशन को फिर से ट्रिगर करें

remember एपीआई का इस्तेमाल अक्सर MutableState के साथ किया जाता है:

var name by remember { mutableStateOf("") }

यहां, remember फ़ंक्शन का इस्तेमाल करने से, MutableState वैल्यू को फिर से कंपोज़ किया जा सकता है.

आम तौर पर, remember एक calculation लैम्डा पैरामीटर लेता है. remember को पहली बार चलाने पर, यह calculation लैंबडा को शुरू करता है और उसके नतीजे को सेव करता है. रीकंपोज़िशन के दौरान, remember पिछली बार सेव की गई वैल्यू दिखाता है.

कैशिंग की स्थिति के अलावा, remember का इस्तेमाल करके, कंपोज़िशन में किसी भी ऑब्जेक्ट या ऑपरेशन के ऐसे नतीजे को सेव किया जा सकता है जिसे शुरू करने या जिसकी गणना करने में ज़्यादा समय लगता है. ऐसा हो सकता है कि आपको हर बार रीकंपोज़िशन में इस गणना को दोहराना न पड़े. उदाहरण के लिए, इस ShaderBrush ऑब्जेक्ट को बनाना, एक महंगा ऑपरेशन है:

val brush = remember {
    ShaderBrush(
        BitmapShader(
            ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
            Shader.TileMode.REPEAT,
            Shader.TileMode.REPEAT
        )
    )
}

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

यहां दिए गए उदाहरणों में बताया गया है कि यह तरीका कैसे काम करता है.

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

@Composable
private fun BackgroundBanner(
    @DrawableRes avatarRes: Int,
    modifier: Modifier = Modifier,
    res: Resources = LocalContext.current.resources
) {
    val brush = remember(key1 = avatarRes) {
        ShaderBrush(
            BitmapShader(
                ImageBitmap.imageResource(res, avatarRes).asAndroidBitmap(),
                Shader.TileMode.REPEAT,
                Shader.TileMode.REPEAT
            )
        )
    }

    Box(
        modifier = modifier.background(brush)
    ) {
        /* ... */
    }
}

अगले स्निपेट में, स्टेट को प्लेन स्टेट होल्डर क्लास MyAppState में होस्ट किया गया है. यह rememberMyAppState फ़ंक्शन को दिखाता है, ताकि remember का इस्तेमाल करके क्लास के इंस्टेंस को शुरू किया जा सके. कंपोज़ में, ऐसे फ़ंक्शन को दिखाना एक सामान्य पैटर्न है. इससे एक ऐसा इंस्टेंस बनाया जा सकता है जो रइकंपोज़िशन के बाद भी बना रहता है. rememberMyAppState फ़ंक्शन को windowSizeClass मिलता है, जो remember के लिए key पैरामीटर के तौर पर काम करता है. अगर यह पैरामीटर बदलता है, तो ऐप्लिकेशन को नई वैल्यू के साथ प्लेन स्टेट होल्डर क्लास को फिर से बनाना होगा. ऐसा तब हो सकता है, जब उपयोगकर्ता डिवाइस को घुमाता है.

@Composable
private fun rememberMyAppState(
    windowSizeClass: WindowSizeClass
): MyAppState {
    return remember(windowSizeClass) {
        MyAppState(windowSizeClass)
    }
}

@Stable
class MyAppState(
    private val windowSizeClass: WindowSizeClass
) { /* ... */ }

Compose, क्लास के equals फ़ंक्शन का इस्तेमाल करके यह तय करता है कि कोई कुंजी बदली है या नहीं. अगर कुंजी बदल गई है, तो वह सेव की गई वैल्यू को अमान्य कर देता है.

रीकंपोज़िशन के बाद भी कुंजियों के साथ स्थिति सेव करना

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

यहां दिए गए उदाहरण में, rememberSaveable कुकी userTypedQuery तक सेव रहती है. इसके बाद, typedQuery में बदलाव हो जाता है:

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

ज़्यादा जानें

स्टेट और Jetpack Compose के बारे में ज़्यादा जानने के लिए, यहां दिए गए अतिरिक्त संसाधन देखें.

सैंपल

कोडलैब

वीडियो

ब्लॉग