स्थिति और 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 creates an observable MutableState<T>, which is an observable type integrated with the compose runtime.

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

Groovy

dependencies {
      ...
      implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.7"
}
  • 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.9.0")
}

Groovy

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

Kotlin

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

Groovy

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

Kotlin

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

Groovy

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

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

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)
    ) {
        /* ... */
    }
}

अगले स्निपेट में, 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 के बारे में ज़्यादा जानने के लिए, यहां दिए गए अतिरिक्त संसाधन देखें.

सैंपल

कोडलैब

वीडियो

ब्लॉग