از نسخه Navigation 3 1.2.0 به بعد، میتوانید با استفاده از API ResultEventBus ، نتایج را از مقصدها برگردانید.
ResultEventBus دو مدل ارتباطی ارائه میدهد:
- نتایج مبتنی بر رویداد : برای رویدادهای گذرا و یکباره (مانند نمایش یک اسنکبار تأیید یا ایجاد یک عارضه جانبی) با استفاده از
ResultEffect. - نتایج مبتنی بر وضعیت : برای مشاهده آخرین نتیجه به عنوان Compose
Stateبا استفاده ازconflateAsState.
تنظیم گذرگاه رویداد نتیجه
برای اینکه ResultEventBus برای مقاصد ترکیبپذیر شما در دسترس باشد، rememberResultEventBusNavEntryDecorator را به لیست دکوراتورهای ارسالی به NavDisplay خود اضافه کنید. این کار محتوای هر مقصد را با یک ترکیب LocalResultEventBus محلی فراهم میکند.
NavDisplay( /* ... */ entryDecorators = listOf( rememberSaveableStateHolderNavEntryDecorator(), rememberResultEventBusNavEntryDecorator() ) )
کلیدهای نتیجه
ResultEventBus هر نتیجه را با استفاده از یک کلید شناسایی و مسیریابی میکند. فرستندهها و گیرندهها با استفاده از همان کلید، نتایج را مطابقت میدهند.
شما میتوانید کلیدهای نتیجه را به دو روش مشخص کنید:
- کلیدهای صریح : میتوانید یک کلید صریح (مانند
resultKey = "pickup_address") مشخص کنید. هنگام بازگرداندن انواع رایج (مانندString،Booleanیا primitives) یا زمانی که چندین مقصد نمونههای مختلفی از یک نوع داده را برمیگردانند، از کلیدهای صریح استفاده کنید. - کلیدهای مشتقشده از نوع : وقتی کلید صریحی مشخص نمیکنید،
ResultEventBusبهطور خودکار با استفاده از نمایشtoStringازKClassنوع نتیجه (مانندContact::class.toString()) یک کلید تولید میکند. از کلیدهای مشتقشده از نوع برای انواع داده متمایز و مختص دامنه استفاده کنید.
نتایج را از یک مقصد برگردانید
برای اینکه کامپوننتهای صفحه نمایش قابل استفاده مجدد و تست باشند، مستقیماً درون رابط کاربری صفحه نمایش خود به LocalResultEventBus دسترسی پیدا نکنید. در عوض، لامبداهای callback را از صفحه نمایش خود در معرض نمایش قرار دهید. در entryProvider خود، با ارسال نتیجه با استفاده از LocalResultEventBus.current و پیمایش به عقب، callback را مدیریت کنید.
شما میتوانید نتایج را با استفاده از یک کلید نتیجه صریح ارسال کنید:
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 ): تمام نتایج منتشر شده برای کلید را به ترتیب پردازش میکند. | رویدادهای یکباره و عوارض جانبی (مانند نمایش یک snackbar یا ارسال به ViewModel ). |
conflateAsState | Conlated : نتایج میانی را حذف میکند و فقط آخرین نتیجه را به عنوان Compose State نگه میدارد. | اصلاحکنندههای سبک وضعیت رابط کاربری (مانند تگهای فیلتر فعال یا لغو انتخاب). |
مدیریت رویدادهای یکباره با ResultEffect
هنگام مدیریت رویدادهای یکباره مانند راهاندازی تجزیه و تحلیل، نمایش یک snackbar یا ارسال نتیجه به ViewModel ، ResultEffect استفاده کنید.
ResultEffect یک صف برای نتایج ورودی نگه میدارد. اگر چندین نتیجه برای یک کلید مشخص ارسال شود، ResultEffect هر نتیجه را به ترتیبی که ارسال شده است پردازش میکند. علاوه بر این، ResultEffect در یک محدودهی کوروتین اجرا میشود که به شما امکان میدهد توابع معلقکننده را مستقیماً درون بدنهی effect فراخوانی کنید.
میتوانید به نتایج مرتبط با یک کلید نتیجهی صریح گوش دهید:
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از ترکیب خارج میشود و گوش دادن به نتایج را متوقف میکند.
مشاهده آخرین نتایج به صورت state با استفاده از 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 با استفاده از 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>() ) پاک کنید. برای جزئیات بیشتر در مورد تطبیق کلید، به Result keys مراجعه کنید.
دستور پختها
برای مثالهای کامل کد قابل اجرا که استراتژیهای مختلف انتقال نتیجه را نشان میدهند، به دستور العملهای زیر مراجعه کنید: