بدءًا من الإصدار 1.2.0 من Navigation 3، يمكنك عرض
النتائج من الوجهات باستخدام واجهة برمجة التطبيقات 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 مباشرةً داخل واجهة مستخدم الشاشة. بدلاً من ذلك، يمكنك عرض دوال lambda لعمليات الاستدعاء من شاشتك. في 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 |
Conflated: يتم تجاهل النتائج المتوسطة والاحتفاظ بأحدث نتيجة فقط كـ Compose State. |
معدِّلات حالة واجهة المستخدم البسيطة (مثل علامات الفلاتر النشطة أو عمليات إلغاء الاختيار) |
التعامل مع الأحداث التي تقع لمرة واحدة باستخدام 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 من خلال
تسلسل مراحل النشاط التالي:
- المرسِل يُرسل: تُرسل وجهة المرسِل نتيجة باستخدام
resultBus.sendResult(resultKey = "pickup_address", address)وتُزيل الأنشطة السابقة. - يدخل المستلِم إلى التركيبة: تصبح وجهة المستلِم هي الشاشة النشطة، ويبدأ
ResultEffectفي الاستماع إلى النتائج. - معالجة النتائج من قِبل المستلِم: يتلقّى
ResultEffectالنتائج وينفّذ محتوى التأثير لكل نتيجة يتم إرسالها لهذا المفتاح، ويعالج جميع الانبعاثات بالترتيب الذي تم إرسالها به. - مغادرة الوجهة المستقبلة لـ Composition: عند إزالة الوجهة المستقبلة من الأنشطة السابقة، يغادر
ResultEffectComposition ويتوقف عن الاستماع إلى النتائج.
مراقبة أحدث النتائج حسب الولاية مع 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>()). للحصول على تفاصيل حول مطابقة
المفاتيح، يُرجى الاطّلاع على مفاتيح النتائج.
وصفات طعام
For complete runnable code examples demonstrating different result-passing strategies, see the following recipes: