از Navigation 3 1.2.0، میتوانید نتایج را از مقصدها بااستفاده از
ResultEventBus API برگردانید.
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() } ) }
دریافت نتایج
مقصدها میتوانند نتایج را بااستفاده از جلوههای مبتنی بر رویداد یا مشاهدات مبتنی بر وضعیت مصرف کنند.
| API | رفتار | موارد استفاده توصیهشده |
|---|---|---|
ResultEffect |
در صف: همه نتایج منتشرشده برای کلید را بهترتیب پردازش میکند. | رویدادهای یکباره و عوارض جانبی (مانند نمایش اسنکبار یا بازارسال به ViewModel). |
conflateAsState |
Conflated: نتایج میانی را حذف میکند و فقط آخرین نتیجه را بهعنوان Compose State نگه میدارد. |
اصلاحکنندههای سبک وضعیت میانای کاربر (مانند برچسبهای فیلتر فعال یا لغو انتخاب). |
مدیریت رویدادهای یکباره با 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 ازطریق
دنباله چرخه حیات زیر اجرا میشود:
- فرستنده منتشر میکند: مقصد فرستنده نتیجهای را بااستفاده از
resultBus.sendResult(resultKey = "pickup_address", address)ارسال میکند و پشته قبلیها را بالا میآورد. - گیرنده وارد ترکیببندی میشود: مقصد گیرنده به صفحه فعال تبدیل میشود و
ResultEffectشروع به گوش دادن برای نتایج میکند. - گیرنده نتایج را پردازش میکند:
ResultEffectبدنه تأثیر خود را برای هر نتیجه ارسالشده برای آن کلید دریافت و اجرا میکند و همه انتشارها را بهترتیبی که ارسال شدهاند پردازش میکند. - گیرنده ترکیببندی را ترک میکند: وقتی مقصد گیرنده از پشته قبلیها خارج میشود،
ResultEffectترکیببندی را ترک میکند و گوش دادن به نتایج را متوقف میکند.
مشاهده جدیدترین نتایج بهعنوان وضعیت با conflateAsState
وقتی فقط به آخرین مقدار نتیجه برای اصلاح یا فیلتر کردن مستقیم وضعیت میانای کاربری محلی نیاز دارید و میخواهید Compose هر زمان که نتیجه بهروز میشود بهطور خودکار بازترکیب کند، conflateAsState را در ResultEventBus فراخوانی کنید.
میتوانید نتایج مرتبط با یک کلید نتیجه صریح را مشاهده کنید:
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 ResultEventBus خودش را بهطور داخلی بااستفاده از rememberResultEventBus ایجاد میکند و بهخاطر میسپارد.
در شرایط زیر میتوانید بهطور صریح یک 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>()) پاک کنید. برای جزئیات مربوط به
مطابقت کلید، به کلیدهای نتیجه مراجعه کنید.
دستور پخت
برای نمونههای کامل کد قابلاجرا که استراتژیهای مختلف ارسال نتیجه را نشان میدهند، دستورالعملهای زیر را ببینید: