नतीजे देखें

Navigation 3 1.2.0 से, ResultEventBus एपीआई का इस्तेमाल करके, डेस्टिनेशन से नतीजे दिखाए जा सकते हैं.

ResultEventBus में कम्यूनिकेशन के दो मॉडल उपलब्ध हैं:

  • इवेंट पर आधारित नतीजे: कुछ समय के लिए होने वाले, एक बार के इवेंट (जैसे, पुष्टि करने वाला स्नैकबार दिखाना या कोई खराब असर ट्रिगर करना) के लिए, ResultEffect का इस्तेमाल करें.
  • स्टेट-बेस्ड नतीजे: conflateAsState का इस्तेमाल करके, Compose State के तौर पर नया नतीजा देखने के लिए.

नतीजे के इवेंट बस को सेट अप करना

ResultEventBus को अपने कंपोज़ेबल डेस्टिनेशन के लिए उपलब्ध कराने के लिए, NavDisplay को पास किए गए डेकोरेटर की सूची में rememberResultEventBusNavEntryDecorator जोड़ें. इससे हर डेस्टिनेशन के कॉन्टेंट को एक LocalResultEventBus कंपोज़िशन लोकल मिलता है.

NavDisplay(
    /* ... */
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        rememberResultEventBusNavEntryDecorator()
    )
)

नतीजे की कुंजियां

ResultEventBus, हर नतीजे की पहचान करता है और उसे कुंजी का इस्तेमाल करके रूट करता है. ईमेल भेजने और पाने वाले लोग, एक ही कुंजी का इस्तेमाल करके नतीजों का मिलान करते हैं.

नतीजे की कुंजियों को दो तरीकों से तय किया जा सकता है:

  • एक्सप्लिसिट की: आपके पास एक्सप्लिसिट की (जैसे, resultKey = "pickup_address") तय करने का विकल्प होता है. एक्सप्लिसिट की का इस्तेमाल तब करें, जब सामान्य टाइप (जैसे, String, Boolean या प्रिमिटिव) दिखाए जा रहे हों या जब कई डेस्टिनेशन, एक ही डेटा टाइप के अलग-अलग इंस्टेंस दिखा रहे हों.
  • टाइप से जनरेट की गई कुंजियां: अगर आपने कोई कुंजी नहीं दी है, तो ResultEventBus, नतीजे के टाइप के KClass (जैसे, Contact::class.toString()) के toString रिप्रज़ेंटेशन का इस्तेमाल करके, अपने-आप एक कुंजी जनरेट करता है. अलग-अलग और डोमेन के हिसाब से डेटा टाइप के लिए, टाइप से जनरेट की गई कुंजियों का इस्तेमाल करें.

किसी डेस्टिनेशन से वापस आने वाली फ़्लाइट

स्क्रीन कंपोज़ेबल को फिर से इस्तेमाल करने और टेस्ट करने लायक बनाए रखने के लिए, सीधे तौर पर अपनी स्क्रीन के यूज़र इंटरफ़ेस (यूआई) में LocalResultEventBus को ऐक्सेस न करें. इसके बजाय, अपनी स्क्रीन से कॉलबैक लैम्ब्डा को एक्सपोज़ करें. अपने entryProvider में, LocalResultEventBus.current का इस्तेमाल करके नतीजा भेजकर और वापस जाकर, कॉलबैक को मैनेज करें.

नतीजे की कुंजी का इस्तेमाल करके, नतीजे भेजे जा सकते हैं:

import androidx.compose.runtime.Composable
import androidx.navigation3.runtime.result.LocalResultEventBus

entry<AddressPickerRoute> {
    val resultBus = LocalResultEventBus.current

    AddressPickerScreen(
        onAddressSelected = { selectedAddress: Address ->
            resultBus.sendResult(
                resultKey = "pickup_address",
                result = selectedAddress
            )
            navigator.goBack()
        }
    )
}

टाइप-डिराइव्ड कुंजी का इस्तेमाल करके भी नतीजे भेजे जा सकते हैं:

import androidx.compose.runtime.Composable
import androidx.navigation3.runtime.result.LocalResultEventBus

entry<ContactPickerRoute> {
    val resultBus = LocalResultEventBus.current

    ContactPickerScreen(
        onContactSelected = { selectedContact: Contact ->
            resultBus.sendResult(result = selectedContact)
            navigator.goBack()
        }
    )
}

नतीजे पाना

डेस्टिनेशन, इवेंट पर आधारित इफ़ेक्ट या स्टेट पर आधारित ऑब्ज़र्वेबल का इस्तेमाल करके, नतीजों का इस्तेमाल कर सकते हैं.

एपीआई व्यवहार इस्तेमाल के सुझाए गए उदाहरण
ResultEffect Queued: यह कुंजी के लिए मिले सभी नतीजों को क्रम से प्रोसेस करता है. एक बार होने वाले इवेंट और खराब असर (जैसे, स्नैकबार दिखाना या ViewModel पर फ़ॉरवर्ड करना).
conflateAsState Conflated: यह बीच के नतीजों को हटा देता है और सिर्फ़ सबसे नए नतीजे को Compose State के तौर पर सेव रखता है. यूज़र इंटरफ़ेस (यूआई) की स्थिति में बदलाव करने वाले लाइटवेट मॉडिफ़ायर (जैसे, चालू फ़िल्टर टैग या चुने गए आइटम को बदलने की सुविधा).

ResultEffect की मदद से, एक बार होने वाले इवेंट मैनेज करना

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

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

किसी खास नतीजे की कुंजी से जुड़े नतीजे सुने जा सकते हैं:

import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation3.runtime.result.ResultEffect

@Composable
fun RideSummaryScreen(
    onOpenAddressPicker: (key: String) -> Unit,
    viewModel: RideSummaryViewModel = viewModel()
) {
    ResultEffect<Address>(resultKey = "pickup_address") { address ->
        viewModel.onPickupAddressSelected(address)
    }

    ResultEffect<Address>(resultKey = "destination_address") { address ->
        viewModel.onDestinationAddressSelected(address)
    }

    RideSummaryContent(
        pickupAddress = viewModel.pickupAddress,
        destinationAddress = viewModel.destinationAddress,
        onPickPickup = { onOpenAddressPicker("pickup_address") },
        onPickDestination = { onOpenAddressPicker("destination_address") }
    )
}

टाइप-डिराइव्ड कुंजी का इस्तेमाल करके भी नतीजे सुने जा सकते हैं:

import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation3.runtime.result.ResultEffect

@Composable
fun ComposeMessageScreen(
    onPickContact: () -> Unit,
    snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
    viewModel: ComposeMessageViewModel = viewModel()
) {
    ResultEffect<Contact> { contact ->
        // Suspending calls are supported directly in the effect body
        snackbarHostState.showSnackbar("Selected ${contact.name}")
        viewModel.onRecipientSelected(contact)
    }

    ComposeMessageContent(
        recipient = viewModel.recipient,
        onPickContact = onPickContact
    )
}

एक डेस्टिनेशन से दूसरे डेस्टिनेशन पर नेविगेट करते समय, ResultEffect इस लाइफ़साइकल क्रम के ज़रिए लागू होता है:

  1. resultBus.sendResult(resultKey = "pickup_address", address) का इस्तेमाल करके, सेंडर डेस्टिनेशन कोई नतीजा भेजता है और बैक स्टैक को पॉप करता है.
  2. रिसीवर, कंपोज़िशन में शामिल होता है: रिसीवर डेस्टिनेशन, ऐक्टिव स्क्रीन बन जाता है और ResultEffect नतीजों को सुनना शुरू कर देता है.
  3. रिसीवर नतीजों को प्रोसेस करता है: ResultEffect को उस कुंजी के लिए भेजे गए हर नतीजे के लिए, इफ़ेक्ट बॉडी मिलती है और उसे लागू किया जाता है. साथ ही, सभी उत्सर्जन को उसी क्रम में प्रोसेस किया जाता है जिस क्रम में उन्हें भेजा गया था.
  4. रिसीवर, कंपोज़िशन से बाहर निकल जाता है: जब रिसीवर डेस्टिनेशन को पिछली गतिविधियों से पॉप किया जाता है, तो ResultEffect कंपोज़िशन से बाहर निकल जाता है और नतीजों को सुनना बंद कर देता है.

conflateAsState के साथ, राज्य के हिसाब से ताज़ा नतीजे देखें

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

किसी खास नतीजे की कुंजी से जुड़े नतीजे देखे जा सकते हैं:

import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.navigation3.runtime.result.LocalResultEventBus

@Composable
fun ThemePreviewScreen(
    onOpenColorPicker: (key: String) -> Unit
) {
    val resultBus = LocalResultEventBus.current

    val primaryColor by resultBus.conflateAsState<Color>(
        resultKey = "primary_color",
        defaultValue = MaterialTheme.colorScheme.primary
    )

    val accentColor by resultBus.conflateAsState<Color>(
        resultKey = "accent_color",
        defaultValue = MaterialTheme.colorScheme.tertiary
    )

    ThemePreviewContent(
        primaryColor = primaryColor,
        accentColor = accentColor,
        onPickPrimary = { onOpenColorPicker("primary_color") },
        onPickAccent = { onOpenColorPicker("accent_color") }
    )
}

टाइप-डिराइव्ड कुंजी का इस्तेमाल करके भी नतीजे देखे जा सकते हैं:

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.navigation3.runtime.result.LocalResultEventBus

@Composable
fun FilterableProductListScreen(
    initialFilter: ProductFilter = ProductFilter.All,
    onOpenFilterPicker: () -> Unit
) {
    val resultBus = LocalResultEventBus.current

    // Observe latest filter result as Compose State, starting with initialFilter
    val activeFilter by resultBus.conflateAsState<ProductFilter>(
        defaultValue = initialFilter
    )

    ProductListContent(
        activeFilter = activeFilter,
        onOpenFilterPicker = onOpenFilterPicker
    )
}

Hoist ResultEventBus

डिफ़ॉल्ट रूप से, rememberResultEventBusNavEntryDecorator rememberResultEventBus का इस्तेमाल करके, इंटरनल तौर पर अपना ResultEventBus बनाता है और उसे याद रखता है.

ज़रूरत पड़ने पर, साफ़ तौर पर ResultEventBus बनाया और होस्ट किया जा सकता है:

  • ResultEventBus इंस्टेंस को सीधे तौर पर नॉन-कंपोज़ेबल कॉम्पोनेंट या डिपेंडेंसी इंजेक्शन ग्राफ़ में पास करें.
  • डेस्टिनेशन की हैरारकी के बाहर, टॉप-लेवल ऐप्लिकेशन स्कैफ़ोल्डिंग (जैसे, ऐप्लिकेशन बार या नेविगेशन पैनल) से नतीजे भेजें या देखें.

ResultEventBus को होस्ट करने के लिए, इसे rememberResultEventBus का इस्तेमाल करके बनाएं और rememberResultEventBusNavEntryDecorator(resultEventBus) को पास करें:

import androidx.compose.runtime.Composable
import androidx.navigation3.runtime.result.rememberResultEventBus
import androidx.navigation3.runtime.result.rememberResultEventBusNavEntryDecorator
import androidx.navigation3.ui.NavDisplay

// Hoist the ResultEventBus at the top level
val resultEventBus = rememberResultEventBus()

// Pass the hoisted bus to the decorator
val resultEventBusNavEntryDecorator =
    rememberResultEventBusNavEntryDecorator<NavKey>(
        resultEventBus = resultEventBus
    )

NavDisplay(
    /* ... */
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        resultEventBusNavEntryDecorator
    )
)

नतीजे मैनेज करना और मिटाना

जब कोई डेस्टिनेशन एक बार मिलने वाले नतीजे का इस्तेमाल करता है, तो उसे removeResult का इस्तेमाल करके इवेंट बस से हटा दें. इससे बस, नए ऑब्ज़र्वर को पुराने इवेंट फिर से डिलीवर नहीं करती. ऐसा तब होता है, जब डेस्टिनेशन फिर से कंपोज़िशन में शामिल होते हैं:

import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation3.runtime.result.LocalResultEventBus
import androidx.navigation3.runtime.result.ResultEffect

@Composable
fun NotificationSettingsScreen(
    viewModel: NotificationViewModel = viewModel()
) {
    val resultBus = LocalResultEventBus.current

    ResultEffect<ConfirmationResult>(resultKey = "confirm_permission") { confirmation ->
        viewModel.onPermissionConfirmed(confirmation)

        // Clear the result after consumption to prevent re-delivery
        resultBus.removeResult(resultKey = "confirm_permission")
    }
}

नतीजों को साफ़ तौर पर दी गई कुंजी (resultBus.removeResult(resultKey)) या टाइप से मिली कुंजी (resultBus.removeResult<T>()) से मिटाया जा सकता है. कुंजी के मैच होने के बारे में ज़्यादा जानने के लिए, नतीजे की कुंजियां देखें.

रेसिपी

नतीजे पास करने की अलग-अलग रणनीतियों को दिखाने वाले, रन किए जा सकने वाले कोड के उदाहरणों के लिए, यहां दी गई रेसिपी देखें: