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:
- Etkinlik tabanlı sonuçlar:
ResultEffectkullanarak geçici, tek seferlik etkinlikler (ör. onay snackbar'ı gösterme veya yan etki tetikleme) için. - Duruma dayalı sonuçlar:
conflateAsStatekullanarak ComposeStateolarak en son sonucu gözlemlemek için.
Sonuç etkinlik veri yolunu ayarlama
ResultEventBus öğesini composable hedeflerinizde kullanılabilir hale getirmek için rememberResultEventBusNavEntryDecorator öğesini NavDisplay öğenize iletilen dekoratörler listesine ekleyin. Bu sayede her hedefin içeriği, LocalResultEventBus bileşen yereliyle sağlanır.
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 öğeler) 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üretilen anahtarlar: Açık bir anahtar belirtmediğinizde
ResultEventBus, sonuç türününKClass(ör.Contact::class.toString())toStringgösterimini kullanarak otomatik olarak bir anahtar oluşturur. Farklı, alana özgü veri türleri için türden türetilen anahtarları kullanın.
Bir varış noktasından sonuçları döndürme
Ekran composable'larının yeniden kullanılabilir ve test edilebilir olmasını sağlamak için ekran kullanıcı arayüzünüzden doğrudan LocalResultEventBus öğesine erişmeyin. Bunun yerine, ekranınızdan
geri çağırma lambda'larını kullanıma sunun. entryProvider uygulamanızda, sonucu LocalResultEventBus.current kullanarak gönderip geri giderek geri çağırma işlemini gerçekleştirin.
Açık bir sonuç anahtarı kullanarak sonuç 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() } ) }
Türe göre türetilmiş bir anahtar kullanarak da sonuç 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, etkinliğe dayalı efektleri veya duruma dayalı gözlemlenebilirleri kullanarak sonuçları kullanabilir.
| API | Davranış | Önerilen kullanım alanları |
|---|---|---|
ResultEffect |
Sıraya alındı: Anahtar için yayınlanan tüm sonuçları sırayla işler. | Tek seferlik etkinlikler ve yan etkiler (ör. snackbar gösterme veya ViewModel öğesine yönlendirme) |
conflateAsState |
Conflated: Ara sonuçları siler ve yalnızca en son sonucu Compose State olarak saklar. |
Hafif 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
Analizleri tetikleme, snackbar gösterme veya sonucu bir ViewModel öğesine iletme gibi tek seferlik etkinlikleri işlerken ResultEffect kullanın.
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, askıya alma işlevlerini doğrudan efekt gövdesinde çağırmanıza olanak tanıyan bir eş yordam kapsamında çalışır.
Belirli 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") } ) }
Türe göre türetilmiş bir anahtar kullanarak da 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ıyla yürütülür:
- Gönderen yayınlar: Gönderen hedef,
resultBus.sendResult(resultKey = "pickup_address", address)kullanarak bir sonuç gönderir ve eski yığını açar. - Alıcı, oluşturmaya girer: Alıcı hedef, etkin ekran olur ve
ResultEffect, sonuçları dinlemeye başlar. - Alıcı, sonuçları işler:
ResultEffect, ilgili anahtar için gönderilen her sonuç için efekt gövdesini alır ve yürütür. Tüm emisyonları gönderildikleri sırayla işler. - Alıcı, oluşturmadan ayrılır: Alıcı hedef, eski yığından çıkarıldığında
ResultEffect, oluşturmadan ayrılır ve sonuçları dinlemeyi durdurur.
conflateAsState ile en son sonuçları durum olarak gözlemleyin
Yerel kullanıcı arayüzü durumunu doğrudan değiştirmek veya filtrelemek için yalnızca en son sonuç değerine ihtiyacınız olduğunda ve sonuç her güncellendiğinde Compose'un otomatik olarak yeniden oluşturmasını istediğinizde ResultEventBus üzerinde conflateAsState yöntemini çağırın.
Açık bir sonuç anahtarıyla ilişkili sonuçları gözlemleyebilirsiniz:
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 türetilmiş 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 ) }
Hoist ResultEventBus
Varsayılan olarak rememberResultEventBusNavEntryDecorator, rememberResultEventBus kullanarak kendi ResultEventBus değerini dahili olarak oluşturur ve hatırlar.
Aşağıdaki durumlarda açıkça bir ResultEventBus oluşturup yukarı taşıyabilirsiniz:
ResultEventBusörneğini doğrudan, composable olmayan bileşenlere veya bağımlılık ekleme grafiklerine iletin.- Hedef hiyerarşisinin dışındaki üst düzey uygulama iskeletinden (ör. uygulama çubuğu veya gezinme çekmecesi) sonuçları gönderin veya gözlemleyin.
ResultEventBus öğesini yukarı taşımak 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 bir sonuç kullandığında removeResult kullanarak sonucu etkinlik veri yolundan temizleyin. Bu sayede, hedefler yeniden oluşturmaya girdiğinde veri yolu, geçmiş etkinlikleri yeni gözlemcilere yeniden göndermez:
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şleştirme hakkında ayrıntılı bilgi için Sonuç anahtarları bölümüne bakın.
Yemek tarifleri
Farklı sonuç iletme stratejilerini gösteren çalıştırılabilir kod örneklerinin tamamı için aşağıdaki tariflere bakın: