नतीजे देखें

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

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

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

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

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

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

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

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

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

  • एक्सप्लिसिट कुंजियां: एक्सप्लिसिट कुंजी (जैसे कि resultKey = "pickup_address") तय की जा सकती है. सामान्य टाइप (जैसे कि String, Boolean या प्रिमिटिव) दिखाने के लिए, एक्सप्लिसिट कुंजियों का इस्तेमाल करें. इसके अलावा, जब कई डेस्टिनेशन एक ही डेटा टाइप के अलग-अलग इंस्टेंस दिखाते हैं, तब भी एक्सप्लिसिट कुंजियों का इस्तेमाल करें.
  • टाइप से मिली कुंजियां: जब कोई कुंजी साफ़ तौर पर तय नहीं की जाती है, तो ResultEventBus, नतीजे के टाइप के toString के KClass (जैसे कि Contact::class.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 कतार में है: इस मोड में, किसी कुंजी के लिए मिले सभी नतीजों को क्रम से प्रोसेस किया जाता है. एक बार होने वाले इवेंट और साइड इफ़ेक्ट (जैसे, स्नैकबार दिखाना या ViewModel पर फ़ॉरवर्ड करना).
conflateAsState मिलाकर जवाब देना: इसमें बीच के नतीजे हटा दिए जाते हैं और सिर्फ़ सबसे नया नतीजा, कंपोज़ State के तौर पर दिखाया जाता है. लाइटवेट यूज़र इंटरफ़ेस (यूआई) की स्थिति में बदलाव करने वाले (जैसे कि चालू फ़िल्टर टैग या चुने गए आइटम को बदलने की सुविधा).

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

ResultEffect का इस्तेमाल तब करें, जब आपको एक बार होने वाले इवेंट मैनेज करने हों. जैसे, Analytics को ट्रिगर करना, स्नैकबार दिखाना या 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. Receiver leaves composition: When the receiver destination is popped from the back stack, ResultEffect leaves composition and stops listening for results.

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>()) के हिसाब से हटाया जा सकता है. कुंजी मिलान के बारे में ज़्यादा जानने के लिए, नतीजे की कुंजियां देखें.

रेसिपी

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