ফলাফল রিটার্ন করা

Navigation 3 1.2.0 থেকে শুরু করে, আপনি ResultEventBus API ব্যবহার করে গন্তব্য থেকে ফলাফল ফেরত পেতে পারেন।

ResultEventBus দুটি কমিউনিকেশন মডেল প্রদান করে:

  • ইভেন্ট-ভিত্তিক ফলাফল: ResultEffect ব্যবহার করে ক্ষণস্থায়ী, এককালীন ইভেন্টের জন্য (যেমন একটি কনফার্মেশন স্ন্যাকবার দেখানো বা একটি পার্শ্ব প্রতিক্রিয়া ট্রিগার করা)।
  • স্টেট-ভিত্তিক ফলাফল: conflateAsState ব্যবহার করে Compose State-এর মতো লেটেস্ট ফলাফল দেখার জন্য।

ফলাফল ইভেন্ট বাস সেট-আপ করুন

আপনার কম্পোজেবল ডেস্টিনেশনে ResultEventBus উপলভ্য করতে, আপনার NavDisplay-এ পাস করা ডেকোরেটরের তালিকায় rememberResultEventBusNavEntryDecorator যোগ করুন। এটি প্রতিটি গন্তব্যের কন্টেন্টকে LocalResultEventBus কম্পোজিশন লোকাল প্রদান করে।

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

ফলাফলের 'কী'

ResultEventBus একটি কী ব্যবহার করে প্রতিটি ফলাফল শনাক্ত করে এবং রুট করে। প্রেরক ও প্রাপক একই 'কী' ব্যবহার করে ফলাফল ম্যাচ করেন।

আপনি দুটি উপায়ে ফলাফল কী নির্দিষ্ট করতে পারেন:

  • এক্সপ্লিসিট কী: আপনি এক্সপ্লিসিট কী (যেমন resultKey = "pickup_address") নির্দিষ্ট করতে পারেন। সাধারণ ধরনের (যেমন String, Boolean বা প্রিমিটিভ) ডেটা ফেরত দেওয়ার সময় অথবা একাধিক ডেস্টিনেশন একই ডেটা টাইপের বিভিন্ন ইনস্ট্যান্স ফেরত দিলে এক্সপ্লিসিট কী ব্যবহার করুন।
  • টাইপ-ডেরাইভড কী: আপনি কোনও নির্দিষ্ট কী উল্লেখ না করলে, ResultEventBus অটোমেটিক toString ব্যবহার করে একটি কী জেনারেট করে যা ফলাফল টাইপের KClass (যেমন Contact::class.toString()) প্রতিনিধিত্ব করে। স্বতন্ত্র, ডোমেন-নির্দিষ্ট ডেটা টাইপের জন্য টাইপ-ডেরাইভড কী ব্যবহার করুন।

গন্তব্য থেকে ফলাফল দেখান

স্ক্রিন কম্পোজেবলকে পুনর্ব্যবহারযোগ্য এবং পরীক্ষাযোগ্য রাখতে, আপনার স্ক্রিন UI-এর মধ্যে সরাসরি 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()
        }
    )
}

ফলাফল পান

গন্তব্যগুলি ইভেন্ট-ভিত্তিক প্রভাব বা স্টেট-ভিত্তিক পর্যবেক্ষণযোগ্য ব্যবহার করে ফলাফল গ্রহণ করতে পারে।

API আচরণ সাজেস্ট করা ব্যবহারের ক্ষেত্র
ResultEffect সারিতে আছে: 'কী'-এর জন্য নির্গত সব ফলাফল ক্রমানুসারে প্রসেস করে। এককালীন ইভেন্ট এবং সাইড এফেক্ট (যেমন, স্ন্যাকবার দেখানো বা ViewModel-এ ফরওয়ার্ড করা)।
conflateAsState কনফ্লেটেড: মধ্যবর্তী ফলাফল বাদ দেয় এবং Compose State হিসেবে শুধুমাত্র লেটেস্ট ফলাফল রাখে। লাইটওয়েট UI স্টেট মডিফায়ার (যেমন, অ্যাক্টিভ ফিল্টার ট্যাগ বা সিলেকশন ওভাররাইড)।

ResultEffect-এর সাথে এককালীন ইভেন্ট ম্যানেজ করুন

অ্যানালিটিক্স ট্রিগার করা, স্ন্যাকবার দেখানো বা কোনও ViewModel-এ ফলাফল ফরওয়ার্ড করার মতো এককালীন ইভেন্ট ম্যানেজ করার সময় ResultEffect ব্যবহার করুন।

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-এর সাথে স্টেট হিসেবে লেটেস্ট ফলাফল দেখুন

লোকাল UI স্টেট সরাসরি পরিবর্তন বা ফিল্টার করার জন্য আপনার যখন শুধু লেটেস্ট ফলাফল ভ্যালু প্রয়োজন হয় এবং ফলাফল আপডেট হলেই 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>()) ব্যবহার করে ফলাফল মুছে দিতে পারেন। কী ম্যাচিং সম্পর্কে আরও জানতে, ফলাফল কী দেখুন।

রেসিপি

বিভিন্ন ফলাফল-পাসিং স্ট্র্যাটেজি প্রদর্শনকারী সম্পূর্ণ রান করা যায় এমন কোডের উদাহরণের জন্য, নিম্নলিখিত রেসিপি দেখুন: