स्थिति और Jetpack Compose

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

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

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

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

स्टेट और कंपोज़िशन

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

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.9.4")
}

Groovy

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

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

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

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

  • LiveData: observeAsState()

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

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

Kotlin

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

Groovy

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

Kotlin

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

Groovy

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

Kotlin

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

Groovy

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

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

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, avatarRes को key1 पैरामीटर के तौर पर लेता है. यह चुनी गई बैकग्राउंड इमेज होती है. अगर 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)
    ) {
        /* ... */
    }
}

अगले स्निपेट में, state को प्लेन स्टेट होल्डर क्लास MyAppState में ले जाया गया है. यह rememberMyAppState फ़ंक्शन को दिखाता है, ताकि remember का इस्तेमाल करके क्लास के इंस्टेंस को शुरू किया जा सके. ऐसे फ़ंक्शन को इस तरह से इस्तेमाल करना कि वे रीकंपोज़िशन के बाद भी बने रहें, Compose में एक सामान्य पैटर्न है. 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 के बारे में ज़्यादा जानने के लिए, यहां दिए गए अतिरिक्त संसाधन देखें.

सैंपल

कोडलैब

वीडियो

ब्लॉग