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

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

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

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

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

আপনার কম্পোজ করা যায় এমন গন্তব্যের জন্য 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-এর মাধ্যমে এককালীন ইভেন্ট ম্যানেজ করা

এককালীন ইভেন্ট ম্যানেজ করার সময় 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-এর সাথে রাজ্য হিসেবে লেটেস্ট ফলাফল দেখুন

আপনি যদি সরাসরি লোকাল 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>()) ব্যবহার করে ফলাফল মুছে দিতে পারেন। কী ম্যাচিংয়ের বিবরণ পেতে, ফলাফলের কী দেখুন।

রেসিপি

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