नेविगेशन की स्थिति सेव करना और मैनेज करना

इन सेक्शन में, बैक स्टैक को सेव करने और बैक स्टैक में मौजूद एंट्री से जुड़ी स्थिति को सेव करने की रणनीतियों के बारे में बताया गया है.

पिछली ऐक्टिविटी को सेव करना

उपयोगकर्ताओं को बेहतर अनुभव देने के लिए, यह ज़रूरी है कि आपके ऐप्लिकेशन की नेविगेशन स्थिति, लाइफ़साइकल के अलग-अलग इवेंट में बनी रहे. इनमें कॉन्फ़िगरेशन में बदलाव और प्रोसेस बंद होना शामिल है. Navigation 3 में, बैक स्टैक का मालिकाना हक आपके पास होता है. इसलिए, इसे बनाने या सेव करने के तरीके के बारे में कोई सख्त दिशा-निर्देश नहीं हैं. हालांकि, Navigation 3 में एक ऐसा तरीका उपलब्ध है जिससे आपको सेव किया जा सकने वाला बैक स्टैक मिलता है: rememberNavBackStack.

rememberNavBackStack का इस्तेमाल करें

rememberNavBackStack कंपोज़ेबल फ़ंक्शन को, बैक स्टैक बनाने के लिए डिज़ाइन किया गया है. यह बैक स्टैक, कॉन्फ़िगरेशन में होने वाले बदलावों और प्रोसेस के बंद होने के बाद भी बना रहता है.

rememberNavBackStack के सही तरीके से काम करने के लिए, आपके बैक स्टैक में मौजूद हर कुंजी को कुछ ज़रूरी शर्तों का पालन करना होगा:

  • NavKey इंटरफ़ेस लागू करें: बैक स्टैक में मौजूद हर कुंजी को NavKey इंटरफ़ेस लागू करना होगा. यह एक मार्कर इंटरफ़ेस के तौर पर काम करता है. यह लाइब्रेरी को यह सूचना देता है कि कुंजी को सेव किया जा सकता है.
  • @Serializable एनोटेशन मौजूद हो: NavKey लागू करने के साथ-साथ, आपकी मुख्य क्लास और ऑब्जेक्ट को @Serializable एनोटेशन के साथ मार्क किया जाना चाहिए.

यहां दिए गए स्निपेट में, rememberNavBackStack को सही तरीके से लागू करने का तरीका बताया गया है:

@Serializable
data object Home : NavKey

@Composable
fun NavBackStack() {
    val backStack = rememberNavBackStack(Home)
}

NavKey के सबटाइप के साथ बैक स्टैक को याद रखना

rememberNavBackStack कंपोज़ेबल फ़ंक्शन, NavBackStack<NavKey> दिखाता है. अगर आपका ऐप्लिकेशन, NavKey का अपना सबटाइप तय करता है, जिससे उसकी सभी कुंजियां इनहेरिट होती हैं, तो कस्टम रिमेंबर फ़ंक्शन को लागू करके, उस टाइपिंग को सुरक्षित रखा जा सकता है. इसके लिए, यह तरीका अपनाएं:

@Serializable
sealed interface MyAppNavKey : NavKey

@Serializable
data object ScreenA: MyAppNavKey

@Serializable
data class ScreenB(val id: String): MyAppNavKey

@Composable
fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> {
    return rememberSerializable(serializer = serializer()) {
        NavBackStack(*elements)
    }
}

@Composable
fun MyApp() {
    // defaultNavBackStack is NavBackStack<NavKey>
    val defaultNavBackStack = rememberNavBackStack(ScreenA)
    // myAppNavBackStack is NavBackStack<MyAppNavKey>
    val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA)
}

ज़्यादा उदाहरणों के लिए, NavBackStackSamples देखें. इसमें ओपन पॉलीमॉर्फ़िज़्म को हैंडल करने का तरीका भी शामिल है.

अन्य विकल्प: ViewModel में सेव करना

बैक स्टैक को मैनेज करने का एक और तरीका है. इसे ViewModel में सेव किया जा सकता है. ViewModel या किसी अन्य कस्टम स्टोरेज का इस्तेमाल करते समय, प्रोसेस बंद होने के बाद भी डेटा को बनाए रखने के लिए, आपको ये काम करने होंगे:

  • पक्का करें कि आपकी कुंजियां क्रम से लगाई जा सकती हों: rememberNavBackStack की तरह ही, आपकी नेविगेशन कुंजियों को क्रम से लगाया जा सकता हो.
  • सीरियलाइज़ेशन और डीसीरियलाइज़ेशन को मैन्युअल तरीके से मैनेज करें: जब आपका ऐप्लिकेशन बैकग्राउंड में जाता है या उसे वापस लाया जाता है, तब आपको हर कुंजी के सीरियलाइज़ किए गए वर्शन को परसिस्टेंट स्टोरेज (जैसे कि SharedPreferences, डेटाबेस या फ़ाइल) में मैन्युअल तरीके से सेव करना होगा. साथ ही, उसे वहां से डीसीरियलाइज़ करना होगा.

ViewModel सेकंड से NavEntry सेकंड तक के वीडियो को टारगेट करना

ViewModels का इस्तेमाल, कॉन्फ़िगरेशन में होने वाले बदलावों के दौरान यूज़र इंटरफ़ेस (यूआई) से जुड़ी स्थिति को बनाए रखने के लिए किया जाता है. जैसे, स्क्रीन रोटेशन. डिफ़ॉल्ट रूप से, ViewModels को सबसे नज़दीकी ViewModelStoreOwner के हिसाब से तय किया जाता है. आम तौर पर, यह आपका Activity या Fragment होता है.

हालांकि, ऐसा हो सकता है कि आपको पूरे Activity के बजाय, बैक स्टैक में मौजूद किसी खास NavEntry (यानी कि किसी खास स्क्रीन या डेस्टिनेशन) के लिए ViewModel को स्कोप करना हो. इससे यह पक्का होता है कि ViewModel की स्थिति सिर्फ़ तब तक बनी रहती है, जब तक वह NavEntry बैक स्टैक का हिस्सा होता है. साथ ही, जब NavEntry को पॉप किया जाता है, तब इसे मिटा दिया जाता है.

androidx.lifecycle:lifecycle-viewmodel-navigation3 ऐड-ऑन लाइब्रेरी, एक NavEntryDecorator उपलब्ध कराती है, जिससे यह काम आसानी से किया जा सकता है. यह डेकोरेटर, हर NavEntry के लिए ViewModelStoreOwner उपलब्ध कराता है. जब किसी NavEntry के कॉन्टेंट में ViewModel बनाया जाता है (जैसे, Compose में viewModel() का इस्तेमाल करके), तो यह बैक स्टैक में मौजूद उस NavEntry की कुंजी के हिसाब से अपने-आप स्कोप हो जाता है. इसका मतलब है कि NavEntry को बैक स्टैक में जोड़ने पर, ViewModel बनाया जाता है. साथ ही, इसे हटाने पर मिटा दिया जाता है.

ViewModel को NavEntry के स्कोप में लाने के लिए, NavEntryDecorator का इस्तेमाल करने के लिए, यह तरीका अपनाएं:

  1. अपनी app/build.gradle.kts फ़ाइल में, androidx.lifecycle:lifecycle-viewmodel-navigation3 डिपेंडेंसी जोड़ें.
  2. NavDisplay बनाते समय, entryDecorators की सूची में डिफ़ॉल्ट rememberSaveableStateHolderNavEntryDecorator() जोड़ें.
  3. entryDecorators की सूची में rememberViewModelStoreNavEntryDecorator() जोड़ें.

NavDisplay(
    entryDecorators = listOf(
        // Add the default decorators for managing scenes and saving state
        rememberSaveableStateHolderNavEntryDecorator(),
        // Then add the view model store decorator
        rememberViewModelStoreNavEntryDecorator()
    ),
    backStack = backStack,
    entryProvider = entryProvider { },
)