Navigation 3 1.2.0 sürümünden itibaren, ResultEventBus API'yi kullanarak hedeflerden sonuç döndürebilirsiniz.
ResultEventBus iki iletişim modeli sunar:
- Etkinliğe dayalı sonuçlar:
ResultEffectkullanarak geçici, tek seferlik etkinlikler (ör. onay snackbar'ı gösterme veya yan etki tetikleme) için. - Duruma dayalı sonuçlar:
conflateAsStatekullanarak ComposeStateile ilgili en son sonucu gözlemlemek için.
Sonuç etkinlik veri yolunu ayarlama
ResultEventBus özelliğini birleştirilebilir hedeflerinizde kullanmak için rememberResultEventBusNavEntryDecorator öğesini NavDisplay öğenize iletilen dekoratörler listesine ekleyin. Bu, her hedefteki içeriğe LocalResultEventBus
yerel kompozisyon sağlar.
NavDisplay( /* ... */ entryDecorators = listOf( rememberSaveableStateHolderNavEntryDecorator(), rememberResultEventBusNavEntryDecorator() ) )
Sonuç anahtarları
ResultEventBus, her sonucu bir anahtar kullanarak tanımlar ve yönlendirir. Gönderenler ve alıcılar, aynı anahtarı kullanarak sonuçları eşleştirir.
Sonuç anahtarlarını iki şekilde belirtebilirsiniz:
- Açık anahtarlar: Açık bir anahtar (ör.
resultKey = "pickup_address") belirtebilirsiniz. Ortak türleri (ör.String,Booleanveya temel türler) döndürürken ya da birden fazla hedef aynı veri türünün farklı örneklerini döndürürken açık anahtarları kullanın. - Türden türetilmiş anahtarlar: Açık bir anahtar belirtmediğinizde
ResultEventBus, sonuç türününtoStringKClassgösterimini (ör.Contact::class.toString()) kullanarak otomatik olarak bir anahtar oluşturur. Türden türetilmiş anahtarları farklı, alana özgü veri türleri için kullanın.
Bir hedeften sonuç döndürme
Ekran composable'larının yeniden kullanılabilir ve test edilebilir olması için LocalResultEventBus öğesine doğrudan ekran kullanıcı arayüzünüzden erişmeyin. Bunun yerine, ekranınızdan geri çağırma lambda'larını kullanıma sunun. entryProvider içinde, LocalResultEventBus.current kullanarak sonucu gönderip geri giderek geri aramayı işleyin.
Sonuçları açık bir sonuç anahtarı kullanarak gönderebilirsiniz:
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() } ) }
Sonuçları türden türetilmiş bir anahtar kullanarak da gönderebilirsiniz:
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() } ) }
Sonuçları alma
Hedefler, sonuçları etkinliğe dayalı efektler veya duruma dayalı gözlemlenebilir öğeler kullanarak tüketebilir.
| API | Davranış | Önerilen kullanım alanları |
|---|---|---|
ResultEffect |
Sıraya alınmış: Anahtar için verilen tüm sonuçları sırayla işler. | Tek seferlik etkinlikler ve yan etkiler (ör. snackbar görüntüleme veya ViewModel adresine yönlendirme). |
conflateAsState |
Birleştirilmiş: Ara sonuçları bırakır ve yalnızca en son sonucu Oluştur State olarak tutar. |
Basit kullanıcı arayüzü durumu değiştiricileri (ör. etkin filtre etiketleri veya seçim geçersiz kılmaları). |
ResultEffect ile tek seferlik etkinlikleri yönetme
ResultEffect, Analytics'i tetikleme, snackbar görüntüleme veya sonucu ViewModel'ye yönlendirme gibi tek seferlik etkinlikleri işlerken kullanılır.
ResultEffect, gelen sonuçlar için bir sıra tutar. Belirli bir anahtar için birden fazla sonuç gönderilirse ResultEffect her sonucu gönderildiği sırayla işler. Ayrıca, ResultEffect bir coroutine kapsamında çalışır. Bu sayede, askıya alma işlevlerini doğrudan efekt gövdesinin içinde çağırabilirsiniz.
Uygunsuz bir sonuç anahtarıyla ilişkili sonuçları dinleyebilirsiniz:
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") } ) }
Ayrıca, türden türetilmiş bir anahtar kullanarak sonuçları dinleyebilirsiniz:
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 ) }
Hedefler arasında gezinirken ResultEffect, aşağıdaki yaşam döngüsü sırası üzerinden yürütülür:
- Gönderen yayınlıyor: Gönderen hedef,
resultBus.sendResult(resultKey = "pickup_address", address)kullanarak bir sonuç gönderir ve geri yığını açar. - Alıcı, oluşturma işlemine girer: Alıcı hedefi etkin ekran haline gelir ve
ResultEffectsonuçları dinlemeye başlar. - Alıcı sonuçları işler:
ResultEffect, bu anahtar için gönderilen her sonuç için kendi efekt gövdesini alır ve yürütür. Tüm emisyonları gönderildikleri sırayla işler. - Alıcı, oluşturma işleminden ayrılıyor: Alıcı hedefi eski yığından çıkarıldığında
ResultEffect, oluşturma işleminden ayrılır ve sonuçları dinlemeyi durdurur.
conflateAsState ile en son sonuçları durum olarak gözlemleyin
Yalnızca yerel kullanıcı arayüzü durumunu doğrudan değiştirmek veya filtrelemek için en son sonuç değerine ihtiyacınız olduğunda ve sonuç güncellendiğinde Compose'un otomatik olarak yeniden oluşturulmasını istediğinizde ResultEventBus üzerinde conflateAsState işlevini çağırın.
Aşağıdaki sonuçları inceleyebilirsiniz:
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") } ) }
Sonuçları türe göre oluşturulmuş bir anahtar kullanarak da gözlemleyebilirsiniz:
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 ) }
Kaldıraç ResultEventBus
Varsayılan olarak rememberResultEventBusNavEntryDecorator, rememberResultEventBus kullanarak dahili olarak kendi ResultEventBus değerini oluşturur ve hatırlar.
Aşağıdaki durumlarda açıkça ResultEventBus oluşturup yükseltebilirsiniz:
ResultEventBusörneğini doğrudan birleştirilemeyen bileşenlere veya bağımlılık ekleme grafiklerine aktarın.- Hedef hiyerarşisinin dışında üst düzey uygulama iskeletinden (ör. uygulama çubuğu veya gezinme çekmecesi) sonuç gönderme veya sonuçları gözlemleme.
ResultEventBus öğesini yükseltmek için rememberResultEventBus kullanarak oluşturun ve rememberResultEventBusNavEntryDecorator(resultEventBus) öğesine iletin:
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 ) )
Sonuçları yönetme ve temizleme
Bir hedef tek seferlik sonucu kullandığında removeResult kullanarak etkinlik veri yolundan temizleyin. Bu, hedefler kompozisyona yeniden girdiğinde otobüsün geçmiş etkinlikleri yeni gözlemcilere yeniden iletmesini engeller:
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") } }
Sonuçları açık anahtara (resultBus.removeResult(resultKey)) veya türe göre türetilmiş anahtara (resultBus.removeResult<T>()) göre temizleyebilirsiniz. Anahtar eşleme hakkında ayrıntılı bilgi için Sonuç anahtarları başlıklı makaleyi inceleyin.
Yemek tarifleri
Farklı sonuç iletme stratejilerini gösteren, çalıştırılabilir kod örneklerinin tamamı için aşağıdaki tariflere bakın: