आपकी स्टेट को कहां होस्ट किया गया है और किस लॉजिक की ज़रूरत है, इसके आधार पर अलग-अलग एपीआई का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) की स्टेट को सेव और वापस लाया जा सकता है. हर ऐप्लिकेशन, इसे बेहतर तरीके से हासिल करने के लिए एपीआई के कॉम्बिनेशन का इस्तेमाल करता है.
किसी भी Android ऐप्लिकेशन की गतिविधि या प्रोसेस को फिर से बनाने की वजह से, उसकी यूज़र इंटरफ़ेस (यूआई) की स्थिति मिट सकती है. स्टेट लॉस इन वजहों से हो सकता है:
- कॉन्फ़िगरेशन में बदलाव. कॉन्फ़िगरेशन में बदलाव होने पर, गतिविधि को खत्म करके फिर से बनाया जाता है. हालांकि, ऐसा तब नहीं होता, जब कॉन्फ़िगरेशन में हुए बदलाव को मैन्युअल तरीके से मैनेज किया जाता है.
- सिस्टम की वजह से ऐप्लिकेशन की प्रोसेस बंद होना. ऐप्लिकेशन बैकग्राउंड में चल रहा हो और डिवाइस, मेमोरी जैसे संसाधनों को खाली कर रहा हो, ताकि अन्य प्रोसेस के लिए उनका इस्तेमाल किया जा सके.
इन इवेंट के बाद, ऐप्लिकेशन की स्थिति को बनाए रखना ज़रूरी है, ताकि उपयोगकर्ता को बेहतर अनुभव मिल सके. किस स्थिति को बनाए रखना है, यह आपके ऐप्लिकेशन के यूनीक उपयोगकर्ता फ़्लो पर निर्भर करता है. सबसे सही तरीका यह है कि आपको कम से कम उपयोगकर्ता के इनपुट और नेविगेशन से जुड़ी स्थिति को सेव रखना चाहिए. इसके उदाहरणों में, किसी सूची की स्क्रोल पोज़िशन, उस आइटम का आईडी जिसके बारे में उपयोगकर्ता को ज़्यादा जानकारी चाहिए, उपयोगकर्ता की प्राथमिकताओं का मौजूदा विकल्प या टेक्स्ट फ़ील्ड में डाला गया इनपुट शामिल है.
इस पेज पर, यूज़र इंटरफ़ेस (यूआई) की स्थिति को सेव करने के लिए उपलब्ध एपीआई के बारे में खास जानकारी दी गई है. यह इस बात पर निर्भर करता है कि आपकी स्थिति को कहां होस्ट किया गया है और इसके लिए किस लॉजिक की ज़रूरत है.
यूज़र इंटरफ़ेस (यूआई) का लॉजिक
अगर आपके ऐप्लिकेशन का स्टेट, यूज़र इंटरफ़ेस (यूआई) में होस्ट किया गया है, तो rememberSaveable का इस्तेमाल करके, गतिविधि और प्रोसेस को फिर से बनाने के दौरान स्टेट को बनाए रखा जा सकता है. ऐसा तब किया जा सकता है, जब स्टेट को कंपोज़ेबल फ़ंक्शन या कंपोज़िशन के दायरे में आने वाली सामान्य स्टेट होल्डर क्लास में होस्ट किया गया हो.
यहां दिए गए स्निपेट में, rememberSaveable का इस्तेमाल यूज़र इंटरफ़ेस (यूआई) एलिमेंट की एक बूलियन स्थिति को सेव करने के लिए किया गया है:
@Composable fun ChatBubble( message: Message ) { var showDetails by rememberSaveable { mutableStateOf(false) } ClickableText( text = AnnotatedString(message.content), onClick = { showDetails = !showDetails } ) if (showDetails) { Text(message.timestamp) } }
showDetails एक बूलियन वैरिएबल है. इससे यह पता चलता है कि चैट बबल छोटा किया गया है या बड़ा किया गया है.
rememberSaveable, सेव किए गए इंस्टेंस स्टेट मैकेनिज़्म की मदद से, Bundle में यूज़र इंटरफ़ेस (यूआई) एलिमेंट की स्थिति सेव करता है.
यह बंडल में प्रिमिटिव टाइप को अपने-आप सेव कर सकता है. अगर आपका स्टेट, डेटा क्लास जैसे किसी ऐसे टाइप में सेव है जो प्रिमिटिव नहीं है, तो सेव करने के लिए अलग-अलग तरीकों का इस्तेमाल किया जा सकता है. जैसे, Parcelize एनोटेशन का इस्तेमाल करना, listSaver और mapSaver जैसे Compose एपीआई का इस्तेमाल करना या Compose रनटाइम Saver क्लास को एक्सटेंड करने वाली कस्टम सेवर क्लास को लागू करना. इन तरीकों के बारे में ज़्यादा जानने के लिए, स्टेट को स्टोर करने के तरीके दस्तावेज़ देखें.
यहां दिए गए स्निपेट में, rememberLazyListState Compose एपीआई, LazyListState को सेव करता है. इसमें rememberSaveable का इस्तेमाल करके, LazyColumn या LazyRow की स्क्रोल स्टेट शामिल होती है. यह LazyListState.Saver का इस्तेमाल करता है. यह एक कस्टम सेवर है, जो स्क्रोल की स्थिति को सेव और रीस्टोर कर सकता है. किसी गतिविधि या प्रोसेस को फिर से बनाने के बाद (उदाहरण के लिए, डिवाइस के ओरिएंटेशन को बदलने जैसे कॉन्फ़िगरेशन में बदलाव करने के बाद), स्क्रोल की स्थिति को सेव रखा जाता है.
@Composable fun rememberLazyListState( initialFirstVisibleItemIndex: Int = 0, initialFirstVisibleItemScrollOffset: Int = 0 ): LazyListState { return rememberSaveable(saver = LazyListState.Saver) { LazyListState( initialFirstVisibleItemIndex, initialFirstVisibleItemScrollOffset ) } }
सबसे सही तरीका
rememberSaveable, यूज़र इंटरफ़ेस (यूआई) की स्थिति को सेव करने के लिए, Bundle का इस्तेमाल करता है. इसे अन्य एपीआई भी शेयर करते हैं. ये एपीआई, इसमें डेटा भी सेव करते हैं. जैसे, आपकी गतिविधि में onSaveInstanceState() कॉल. हालांकि, इस Bundle का साइज़ सीमित होता है. साथ ही, बड़े ऑब्जेक्ट को सेव करने से, रनटाइम में TransactionTooLarge अपवाद हो सकते हैं. यह समस्या खास तौर पर, सिंगल Activity ऐप्लिकेशन में हो सकती है. इनमें पूरे ऐप्लिकेशन में एक ही Bundle का इस्तेमाल किया जाता है.
इस तरह के क्रैश से बचने के लिए, आपको बंडल में बड़े जटिल ऑब्जेक्ट या ऑब्जेक्ट की सूचियां सेव नहीं करनी चाहिए.
इसके बजाय, सिर्फ़ ज़रूरी डेटा सेव करें, जैसे कि आईडी या कुंजियां. इनका इस्तेमाल करके, ज़्यादा जटिल यूज़र इंटरफ़ेस (यूआई) की स्थिति को वापस लाने के लिए, अन्य तरीकों का इस्तेमाल करें. जैसे, परसिस्टेंट स्टोरेज.
डिज़ाइन के ये विकल्प, आपके ऐप्लिकेशन के इस्तेमाल के खास उदाहरणों और इस बात पर निर्भर करते हैं कि आपके उपयोगकर्ता इससे किस तरह के व्यवहार की उम्मीद करते हैं.
स्टेट रीस्टोरेशन की पुष्टि करना
आपके पास यह पुष्टि करने का विकल्प है कि आपके Compose एलिमेंट में rememberSaveable के साथ सेव किया गया स्टेटस, गतिविधि या प्रोसेस को फिर से बनाने पर सही तरीके से वापस लाया गया है या नहीं. ऐसा करने के लिए, कुछ खास एपीआई उपलब्ध हैं. जैसे,
StateRestorationTester. ज़्यादा जानने के लिए, टेस्टिंग दस्तावेज़ देखें.
कारोबारी नियम
अगर आपके यूज़र इंटरफ़ेस (यूआई) एलिमेंट की स्थिति को ViewModel में होस्ट किया गया है, क्योंकि कारोबारी नियम के लिए इसकी ज़रूरत है, तो ViewModel के एपीआई का इस्तेमाल किया जा सकता है.
Android ऐप्लिकेशन में ViewModel का इस्तेमाल करने का एक मुख्य फ़ायदा यह है कि यह कॉन्फ़िगरेशन में होने वाले बदलावों को बिना किसी शुल्क के मैनेज करता है. कॉन्फ़िगरेशन में बदलाव होने पर, गतिविधि को खत्म करके फिर से बनाया जाता है. ऐसे में, ViewModel में होइस्ट किया गया यूज़र इंटरफ़ेस (यूआई) स्टेट, मेमोरी में सेव रहता है. फिर से बनाने के बाद, पुराना ViewModel
इंस्टेंस, नई गतिविधि के इंस्टेंस से अटैच हो जाता है.
हालांकि, सिस्टम की ओर से प्रोसेस बंद किए जाने पर, ViewModel इंस्टेंस काम नहीं करता.
यूज़र इंटरफ़ेस (यूआई) की स्थिति को बनाए रखने के लिए, ViewModel के लिए सेव की गई स्थिति वाले मॉड्यूल का इस्तेमाल करें. इसमें SavedStateHandle एपीआई शामिल होता है.
सबसे सही तरीका
SavedStateHandle भी यूज़र इंटरफ़ेस (यूआई) की स्थिति को सेव करने के लिए, Bundle तरीके का इस्तेमाल करता है. इसलिए, आपको इसका इस्तेमाल सिर्फ़ यूज़र इंटरफ़ेस (यूआई) एलिमेंट की स्थिति को सेव करने के लिए करना चाहिए.
स्क्रीन यूज़र इंटरफ़ेस (यूआई) की स्थिति, कारोबार के नियमों को लागू करके और यूज़र इंटरफ़ेस (यूआई) के अलावा, आपके ऐप्लिकेशन की लेयर को ऐक्सेस करके बनाई जाती है. इसे SavedStateHandle में सेव नहीं किया जाना चाहिए, क्योंकि यह जटिल और बड़ी हो सकती है. जटिल या बड़े डेटा को सेव करने के लिए, अलग-अलग तरीकों का इस्तेमाल किया जा सकता है. जैसे, लोकल परसिस्टेंट स्टोरेज. प्रोसेस को फिर से बनाने के बाद, स्क्रीन को फिर से बनाया जाता है. इसके लिए, SavedStateHandle में सेव की गई अस्थायी स्थिति (अगर कोई हो) को पहले जैसा किया जाता है. साथ ही, स्क्रीन के यूज़र इंटरफ़ेस (यूआई) की स्थिति को डेटा लेयर से फिर से जनरेट किया जाता है.
SavedStateHandle एपीआई
SavedStateHandle में यूज़र इंटरफ़ेस (यूआई) एलिमेंट की स्थिति को सेव करने के लिए, अलग-अलग एपीआई होते हैं. इनमें से सबसे अहम एपीआई ये हैं:
लिखें State |
saveable() |
|---|---|
StateFlow |
getStateFlow() |
State को कंपोज़ करें
यूज़र इंटरफ़ेस (यूआई) एलिमेंट की स्थिति को MutableState के तौर पर पढ़ने और लिखने के लिए, SavedStateHandle के saveable एपीआई का इस्तेमाल करें. इससे, कम से कम कोड सेटअप के साथ गतिविधि और प्रोसेस को फिर से बनाने में मदद मिलती है.
saveable एपीआई, प्रिमिटिव टाइप के साथ काम करता है. साथ ही, इसमें stateSaver पैरामीटर मिलता है, ताकि rememberSaveable() की तरह ही कस्टम सेवर का इस्तेमाल किया जा सके.
नीचे दिए गए स्निपेट में, message उपयोगकर्ता के इनपुट को TextField में सेव करता है:
class ConversationViewModel( savedStateHandle: SavedStateHandle ) : ViewModel() { var message by savedStateHandle.saveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } private set fun update(newMessage: TextFieldValue) { message = newMessage } /*...*/ } val viewModel = ConversationViewModel(SavedStateHandle()) @Composable fun UserInput(/*...*/) { TextField( value = viewModel.message, onValueChange = { viewModel.update(it) } ) }
saveable एपीआई का इस्तेमाल करने के बारे में ज़्यादा जानकारी के लिए, SavedStateHandle दस्तावेज़ देखें.
StateFlow
यूज़र इंटरफ़ेस (यूआई) एलिमेंट की स्थिति को सेव करने के लिए, getStateFlow() का इस्तेमाल करें. साथ ही, इसे SavedStateHandle से फ़्लो के तौर पर इस्तेमाल करें. StateFlow को सिर्फ़ पढ़ा जा सकता है. साथ ही, एपीआई के लिए आपको एक कुंजी तय करनी होगी, ताकि आप नई वैल्यू को एमिट करने के लिए फ़्लो को बदल सकें. कॉन्फ़िगर की गई कुंजी की मदद से, StateFlow को वापस पाया जा सकता है और नई वैल्यू इकट्ठा की जा सकती है.
यहां दिए गए स्निपेट में, savedFilterType एक StateFlow वैरिएबल है. यह चैट ऐप्लिकेशन में चैट चैनलों की सूची पर लागू किए गए फ़िल्टर टाइप को सेव करता है:
private const val CHANNEL_FILTER_SAVED_STATE_KEY = "ChannelFilterKey" class ChannelViewModel( channelsRepository: ChannelsRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { private val savedFilterType: StateFlow<ChannelsFilterType> = savedStateHandle.getStateFlow( key = CHANNEL_FILTER_SAVED_STATE_KEY, initialValue = ChannelsFilterType.ALL_CHANNELS ) private val filteredChannels: Flow<List<Channel>> = combine(channelsRepository.getAll(), savedFilterType) { channels, type -> filter(channels, type) }.onStart { emit(emptyList()) } fun setFiltering(requestType: ChannelsFilterType) { savedStateHandle[CHANNEL_FILTER_SAVED_STATE_KEY] = requestType } /*...*/ } enum class ChannelsFilterType { ALL_CHANNELS, RECENT_CHANNELS, ARCHIVED_CHANNELS }
जब भी उपयोगकर्ता कोई नया फ़िल्टर टाइप चुनता है, तब setFiltering को कॉल किया जाता है. इससे SavedStateHandle में एक नई वैल्यू सेव हो जाती है. इसे _CHANNEL_FILTER_SAVED_STATE_KEY_ कुंजी के साथ सेव किया जाता है. savedFilterType एक ऐसा फ़्लो है जो कुंजी में सेव की गई सबसे नई वैल्यू को दिखाता है. filteredChannels को फ़्लो की सदस्यता दी गई है, ताकि चैनल को फ़िल्टर किया जा सके.
getStateFlow() एपीआई के बारे में ज़्यादा जानकारी के लिए, SavedStateHandle दस्तावेज़ देखें.
खास जानकारी
यहां दी गई टेबल में, इस सेक्शन में शामिल एपीआई के बारे में खास जानकारी दी गई है. साथ ही, यूज़र इंटरफ़ेस (यूआई) की स्थिति को सेव करने के लिए, हर एपीआई का इस्तेमाल कब करना चाहिए, इस बारे में भी बताया गया है:
| इवेंट | यूज़र इंटरफ़ेस (यूआई) का लॉजिक | ViewModel में कारोबारी नियम |
|---|---|---|
| कॉन्फ़िगरेशन में बदलाव | rememberSaveable |
ऑटोमैटिक |
| सिस्टम की वजह से ऐप्लिकेशन की प्रोसेस बंद होना | rememberSaveable |
SavedStateHandle |
इस्तेमाल किया जाने वाला एपीआई इस बात पर निर्भर करता है कि स्टेट कहां सेव है और इसके लिए किस लॉजिक की ज़रूरत है. यूज़र इंटरफ़ेस (यूआई) लॉजिक में इस्तेमाल किए जाने वाले स्टेट के लिए, rememberSaveable का इस्तेमाल करें. कारोबारी नियम में इस्तेमाल किए जाने वाले स्टेट के लिए, अगर उसे ViewModel में सेव किया जाता है, तो उसे SavedStateHandle का इस्तेमाल करके सेव करें.
यूज़र इंटरफ़ेस (यूआई) की स्थिति का थोड़ा डेटा सेव करने के लिए, आपको बंडल एपीआई (rememberSaveable और SavedStateHandle) का इस्तेमाल करना चाहिए. यूज़र इंटरफ़ेस (यूआई) को उसकी पिछली स्थिति में वापस लाने के लिए, यह डेटा ज़रूरी है. साथ ही, डेटा सेव करने के अन्य तरीके भी ज़रूरी हैं. उदाहरण के लिए, अगर आपने बंडल में उस प्रोफ़ाइल का आईडी सेव किया है जिसे उपयोगकर्ता देख रहा था, तो डेटा लेयर से प्रोफ़ाइल की जानकारी जैसा ज़्यादा डेटा फ़ेच किया जा सकता है.
यूज़र इंटरफ़ेस (यूआई) की स्थिति को सेव करने के अलग-अलग तरीकों के बारे में ज़्यादा जानने के लिए, यूज़र इंटरफ़ेस (यूआई) की स्थिति को सेव करने से जुड़ा सामान्य दस्तावेज़ और आर्किटेक्चर गाइड का डेटा लेयर पेज देखें.
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर, लिंक टेक्स्ट दिखता है
- स्टेट को कहां होस्ट करना चाहिए
- स्टेट और Jetpack Compose
- सूचियां और ग्रिड