Yan etki, uygulamanın durumunda kapsamı derlenebilir. composables nedeniyle yaşam döngüsü ve özellikleri gibi yeniden besteler, composable'ların farklı sıralarda yeniden kompozisyonlarını yürütme ya da atılabilecek yeniden kompozisyonlar, composable'ların ideal olarak yan etkiye sahip olmalıdır ücretsiz.
Ancak bazen yan etkiler, örneğin tek seferlik bir veya belirli bir anda başka bir ekrana gitme gibi bir etkinlik durum koşulu. Bu işlemler, kontrol edilen bir alanına sahip bir e-posta adresi kullanabilirsiniz. Bu sayfada Jetpack Compose'un sunduğu farklı yan etki API'leri hakkında bilgi edineceksiniz.
Durum ve sonuç kullanım alanları
Oluşturma Konusunda Düşünme bölümünde ele alındığı gibi composable'ların yan etki içermeyen olması gerekir. Bir sonraki aşamaya (bkz. Yönetim resmi belgeler dokümanı) dosyadaki Efekt Efekti'ni Bu yan etkilerin öngörülebilir şekilde yürütülmesi için API'leri devreye sokun.
Compose'da ortaya çıkan farklı olasılık efektleri nedeniyle rahatlıkla aşırı kullanılır. Bu öğelerde yaptığınız işin kullanıcı arayüzüyle Yönetim durumu bölümünde açıklandığı gibi tek yönlü veri akışını bozmaz belgelerine göz atın.
LaunchedEffect
: Askıya alma işlevlerini bir composable kapsamında çalıştırma
Bir composable'ın ömrü boyunca iş yapmak ve
işlevlerini kullanmak için
LaunchedEffect
composable'dan bahsetmek istiyorum. LaunchedEffect
Beste'ye girdiğinde,
ile örtüşen bir işlemdir. Eş yordam
LaunchedEffect
besteden ayrılırsa iptal edilir. LaunchedEffect
ise
yeniden oluşturabilirsiniz (bkz. Yeniden başlatma
Efektler bölümünde yer alırsa mevcut eş yordam,
iptal edildi ve yeni askıya alma işlevi yeni bir eş yordamda kullanıma sunulacak.
Örneğin, burada alfa değerini yapılandırılabilir gecikme:
// Allow the pulse rate to be configured, so it can be sped up if the user is running // out of time var pulseRateMs by remember { mutableStateOf(3000L) } val alpha = remember { Animatable(1f) } LaunchedEffect(pulseRateMs) { // Restart the effect when the pulse rate changes while (isActive) { delay(pulseRateMs) // Pulse the alpha every pulseRateMs to alert the user alpha.animateTo(0f) alpha.animateTo(1f) } }
Yukarıdaki kodda, animasyonda, askıya alma işlevi
delay
gereken süreyi bekleyin. Ardından, çalıştırılan alfa testte
kullanarak tekrar sıfıra dönün ve
animateTo
.
Bu işlem, composable'ın kullanım ömrü boyunca tekrarlanır.
rememberCoroutineScope
: composable dışında bir eş yordam başlatmak için besteye duyarlı bir kapsam elde edin
LaunchedEffect
, composable bir işlev olduğundan yalnızca
composable işlevleri. Bir composable'ın dışında bir eş yordam başlatmak için,
Ancak bu ayardan ayrıldıktan sonra otomatik olarak iptal edilecek şekilde
bileşim, kullanım
rememberCoroutineScope
.
Ayrıca, dönüşüm hunisinin yaşam döngüsünü kontrol etmeniz gerektiğinde rememberCoroutineScope
manuel olarak bir veya daha fazla eş yordamı manuel olarak
gerçekleşmesidir.
rememberCoroutineScope
, şunu döndüren bir composable işlevdir:
CoroutineScope
, bestenin çağrıldığı noktaya bağlıdır. İlgili içeriği oluşturmak için kullanılan
kapsam iptal edilecek.
Önceki örneğe göre, bir Snackbar
değerini göstermek için bu kodu kullanabilirsiniz
Kullanıcı bir Button
düğmesine dokunduğunda:
@Composable fun MoviesScreen(snackbarHostState: SnackbarHostState) { // Creates a CoroutineScope bound to the MoviesScreen's lifecycle val scope = rememberCoroutineScope() Scaffold( snackbarHost = { SnackbarHost(hostState = snackbarHostState) } ) { contentPadding -> Column(Modifier.padding(contentPadding)) { Button( onClick = { // Create a new coroutine in the event handler to show a snackbar scope.launch { snackbarHostState.showSnackbar("Something happened!") } } ) { Text("Press me") } } } }
rememberUpdatedState
: Efektte, değer değişirse yeniden başlatılmaması gereken bir değere başvuru
Anahtar parametrelerden biri değiştiğinde LaunchedEffect
yeniden başlatılır. Ancak,
bazı durumlarda etkinizi yaratmak için kullanabileceğiniz
efektin yeniden başlatılmasını istemezsiniz. Bunu yapmak için de
bu değere referans oluşturmak için rememberUpdatedState
kullanılması gerekir.
kaydedilip güncellenebilir. Bu yaklaşım,
uzun ömürlü, uzun ömürlü, uzun ömürlü operasyonlara,
ayrıntılarına kadar
yeniden başlat.
Örneğin, uygulamanızda, bir süre sonra kaybolan bir LandingScreen
olduğunu varsayalım.
gerekir. LandingScreen
yeniden oluşturulsa bile bir süre bekleyen efekt
ve geçen sürenin yeniden başlatılmaması gerektiğini bildirir:
@Composable fun LandingScreen(onTimeout: () -> Unit) { // This will always refer to the latest onTimeout function that // LandingScreen was recomposed with val currentOnTimeout by rememberUpdatedState(onTimeout) // Create an effect that matches the lifecycle of LandingScreen. // If LandingScreen recomposes, the delay shouldn't start again. LaunchedEffect(true) { delay(SplashWaitTimeMillis) currentOnTimeout() } /* Landing screen content */ }
Telefon araması sitesinin yaşam döngüsüyle eşleşen bir efekt oluşturmak için
Unit
veya true
gibi hiçbir zaman değişmeyen sabit değer parametre olarak iletilir.
yukarıdaki kod LaunchedEffect(true)
kullanılır. onTimeout
lambda always, LandingScreen
tarafından yeniden oluşturulan en son değeri içerir
ile sarmalanması gerekir. onTimeout
, rememberUpdatedState
işleviyle sarmalanmalıdır.
Kodda döndürülen State
, currentOnTimeout
,
etkisi.
DisposableEffect
: Temizlik gerektiren efektler
Tuşlar değiştikten sonra temizlenmesi gereken yan etkiler veya
composable'ın Beste'den ayrılması,
DisposableEffect
.
DisposableEffect
tuşları değişirse composable'ın bu öğeleri imha etmesi gerekir.
geçerli etkisinin olup olmadığını kontrol edin ve efekti tekrar çağırarak sıfırlayın.
Örneğin,
Lifecycle
etkinlik
üzerinde bir
LifecycleObserver
.
Bu etkinlikleri Compose'da dinlemek için DisposableEffect
kullanarak kaydolun ve
ve gerektiğinde gözlemcinin kaydını iptal edebilir.
@Composable fun HomeScreen( lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current, onStart: () -> Unit, // Send the 'started' analytics event onStop: () -> Unit // Send the 'stopped' analytics event ) { // Safely update the current lambdas when a new one is provided val currentOnStart by rememberUpdatedState(onStart) val currentOnStop by rememberUpdatedState(onStop) // If `lifecycleOwner` changes, dispose and reset the effect DisposableEffect(lifecycleOwner) { // Create an observer that triggers our remembered callbacks // for sending analytics events val observer = LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_START) { currentOnStart() } else if (event == Lifecycle.Event.ON_STOP) { currentOnStop() } } // Add the observer to the lifecycle lifecycleOwner.lifecycle.addObserver(observer) // When the effect leaves the Composition, remove the observer onDispose { lifecycleOwner.lifecycle.removeObserver(observer) } } /* Home screen content */ }
Yukarıdaki kodda bu efekt, observer
öğesini
lifecycleOwner
. lifecycleOwner
değişirse efekt kaldırılır ve
yeni lifecycleOwner
ile yeniden başlatıldı.
DisposableEffect
, nihai ifade olarak onDispose
ifadesini içermelidir
kendi kod bloğunda yer alır. Aksi takdirde, IDE'de derleme zamanı hatası gösterilir.
SideEffect
: Oluştur durumunu, Compose olmayan koda yayınla
Oluşturma durumunu, oluşturma tarafından yönetilmeyen nesnelerle paylaşmak için
SideEffect
composable'dan bahsetmek istiyorum. SideEffect
kullanmak, etkinin şu süreden sonra yürütülmesini garanti eder:
en iyi yöntemin
ne olduğunu öğreneceğiz. Diğer yandan,
başarılı bir yeniden besteleme garanti edilmeden önce bir etki göstermesi,
composable'a yazın.
Örneğin, analiz kitaplığınız kullanıcılarınızı segmentlere ayırmanıza
özel meta veriler ekleyerek popülasyon (bu örnekte "kullanıcı özellikleri")
ve sonraki tüm Analytics etkinliklerine
katkıda bulunur. Verinin kullanıcı türünü
analiz kitaplığınıza eklemek için SideEffect
değerini kullanın.
@Composable fun rememberFirebaseAnalytics(user: User): FirebaseAnalytics { val analytics: FirebaseAnalytics = remember { FirebaseAnalytics() } // On every successful composition, update FirebaseAnalytics with // the userType from the current User, ensuring that future analytics // events have this metadata attached SideEffect { analytics.setUserProperty("userType", user.userType) } return analytics }
produceState
: Oluşturma olmayan durumu, Oluştur durumuna dönüştürür
produceState
değerleri bir kampanyaya aktarabilen Besteye ayarlanan
State
döndürüldü. Şunun için kullanın:
Oluşturma dışı durumu Oluşturma durumuna dönüştürebilirsiniz (örneğin, kuruluş dışından URL'yi
bir abonelik temelli kullanıcı durumu (örneğin, Flow
, LiveData
veya RxJava
)
Beste.
produceState
besteye girdiğinde yapımcı başlatılır ve
besteden ayrıldığında iptal edilir. Döndürülen State
şunları içerir:
aynı değerin ayarlanması yeniden besteyi tetiklemez.
produceState
bir eş yordam oluştursa da, gözlemlemek için de kullanılabilir
çalışmayan veri kaynaklarıdır. Bu kaynağa aboneliği kaldırmak için şunu kullanın:
"the"
awaitDispose
işlevini kullanın.
Aşağıdaki örnekteproduceState
ağ. loadNetworkImage
composable işlevi, şunları yapabilecek bir State
döndürür:
başka composable'larda kullanılıyor.
@Composable fun loadNetworkImage( url: String, imageRepository: ImageRepository = ImageRepository() ): State<Result<Image>> { // Creates a State<T> with Result.Loading as initial value // If either `url` or `imageRepository` changes, the running producer // will cancel and will be re-launched with the new inputs. return produceState<Result<Image>>(initialValue = Result.Loading, url, imageRepository) { // In a coroutine, can make suspend calls val image = imageRepository.load(url) // Update State with either an Error or Success result. // This will trigger a recomposition where this State is read value = if (image == null) { Result.Error } else { Result.Success(image) } } }
derivedStateOf
: Bir veya daha fazla durum nesnesini başka bir duruma dönüştürür
Compose'da yeniden düzenleme gerçekleşir. her gözlemlenen durum nesnesi veya composable giriş değiştiğinde. Durum nesnesi veya giriş, kullanıcı arayüzünün güncellenmesi gerekenden daha sık değişiyorsa Bu durum, gereksiz yeniden besteleme yapmaya neden olur.
derivedStateOf
kullanmanız gerekir.
bir composable'a yaptığınız girişler gerekenden daha sık değiştiğinde işlev
çok önemli. Bu durum genellikle şunlar gibi sık sık
bir değişiklik olduğunda ortaya çıkar:
ancak composable'ın yalnızca ilettiğinde buna tepki vermesi gerekiyor.
sağlayabilirsiniz. derivedStateOf
, oluşturduğunuz yeni Oluştur durum nesnesini
yalnızca ihtiyacınız olduğu kadar güncellendiğini görebilirsiniz. Bu şekilde,
Kotlin Akışlarına benzer şekilde
distinctUntilChanged()
operatörümüzü kullanabilirsiniz.
Doğru kullanım
Aşağıdaki snippet, derivedStateOf
için uygun bir kullanım alanını göstermektedir:
@Composable // When the messages parameter changes, the MessageList // composable recomposes. derivedStateOf does not // affect this recomposition. fun MessageList(messages: List<Message>) { Box { val listState = rememberLazyListState() LazyColumn(state = listState) { // ... } // Show the button if the first visible item is past // the first item. We use a remembered derived state to // minimize unnecessary compositions val showButton by remember { derivedStateOf { listState.firstVisibleItemIndex > 0 } } AnimatedVisibility(visible = showButton) { ScrollToTopButton() } } }
Bu snippet'te firstVisibleItemIndex
, ilk görünür öğe her zaman değişir
anlamına gelir. Kaydırırken değer 0
, 1
, 2
, 3
, 4
, 5
vb. olur.
Bununla birlikte, yeniden düzenleme yalnızca değer 0
değerinden büyük olduğunda gerçekleştirilmelidir.
Güncelleme sıklığındaki bu uyumsuzluk, güncelleme sıklığındaki
bu uyuşmazlık,
derivedStateOf
Hatalı kullanım
İki Compose durum nesnesini birleştirdiğinizde
"türetme durumu" olduğundan derivedStateOf
parametresini kullanmalısınız. Ancak bu
aşağıdaki snippet'te gösterildiği gibi tamamen ek yük oluşturur ve gerekli değildir:
// DO NOT USE. Incorrect usage of derivedStateOf. var firstName by remember { mutableStateOf("") } var lastName by remember { mutableStateOf("") } val fullNameBad by remember { derivedStateOf { "$firstName $lastName" } } // This is bad!!! val fullNameCorrect = "$firstName $lastName" // This is correct
Bu snippet'te, fullName
eklentisinin de firstName
ve
lastName
. Bu nedenle, aşırı bir yeniden oluşturma işlemi gerçekleşmez ve
derivedStateOf
gerekli değil.
snapshotFlow
: Compose'un Durumunu Akışlara dönüştür
snapshotFlow
kullanın
State<T>
değerini dönüştürmek için
soğuk Akışa dönüştürebilir. snapshotFlow
, toplanıp yayıldığında blokunu çalıştırır
okunan State
nesnenin sonucu. State
nesneden biri
snapshotFlow
bloğunun içinde nasıl dönüştüğünü öğrenirseniz, Akış yeni değeri ya da
yeni değer şuna eşit değilse toplayıcısına
önceki yayınlanan değer (bu davranış,
Flow.distinctUntilChanged
).
Aşağıdaki örnekte, kullanıcı ekranı kaydırdığında kaydeden bir yan efekt gösterilmektedir listedeki ilk öğeyi analize yapıştırın:
val listState = rememberLazyListState()
LazyColumn(state = listState) {
// ...
}
LaunchedEffect(listState) {
snapshotFlow { listState.firstVisibleItemIndex }
.map { index -> index > 0 }
.distinctUntilChanged()
.filter { it == true }
.collect {
MyAnalyticsService.sendScrolledPastFirstItemEvent()
}
}
Yukarıdaki kodda, listState.firstVisibleItemIndex
, önceki hâliyle
akış operatörlerinin gücünden yararlanabilir.
Yeniden başlatma efektleri
Oluşturma'daki bazı efektler, ör. LaunchedEffect
, produceState
veya
DisposableEffect
,
çalışan efekti iptal edip yeni tuşlarla yeni bir tane başlatın.
Bu API'lerin tipik biçimi şu şekildedir:
EffectName(restartIfThisKeyChanges, orThisKey, orThisKey, ...) { block }
Bu davranışın incelikleri nedeniyle, parametrelerin yalnızca yeniden başlatmak için kullanılanlar doğru olanlar değil:
- Efektleri olması gerekenden daha az yeniden başlatmak uygulamanızda hatalara neden olabilir.
- Efektleri olması gerekenden daha fazla yeniden başlatmak verimsiz olabilir.
Genel bir kural olarak,
kodu, composable efekte parametre olarak eklenmelidir. Bunların dışında,
efektin yeniden başlatılmasını zorunlu kılmak için daha fazla parametre eklenebilir. Eğer
bir değişken etkinin yeniden başlatılmasına neden olmamalıdır, değişken
rememberUpdatedState
içinde. Değişken hiçbir zaman
herhangi bir anahtar olmadan remember
içine yerleştirildiği için
değişkeni bir anahtar olarak geçirebilir.
Yukarıda gösterilen DisposableEffect
kodunda efekt,
lifecycleOwner
bloğunda kullanılır, çünkü bu öğelerde yapılan herhangi bir değişiklik
efektini kullanın.
@Composable
fun HomeScreen(
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
onStart: () -> Unit, // Send the 'started' analytics event
onStop: () -> Unit // Send the 'stopped' analytics event
) {
// These values never change in Composition
val currentOnStart by rememberUpdatedState(onStart)
val currentOnStop by rememberUpdatedState(onStop)
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
/* ... */
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
}
DisposableEffect
olarak currentOnStart
ve currentOnStop
gerekli değil
kullanımı nedeniyle Beste'de hiçbir zaman değişmediğinden
rememberUpdatedState
. Parametre olarak lifecycleOwner
değerini iletmezseniz ve
değişir, HomeScreen
yeniden oluşturur, ancak DisposableEffect
bertaraf edilmez
yeniden başlatıldı. Yanlış lifecycleOwner
olduğundan bu durum sorunlara yol açar.
kullanmaya devam edecek.
Anahtar olarak sabitler
true
gibi bir sabit değeri efekt tuşu olarak kullanabilirsiniz:
telefon araması sitesinin yaşam döngüsünü takip etmesini sağlayın. RACI matrisinde
yukarıda gösterilen LaunchedEffect
örneğine benzer. Ancak bunu yapmadan önce
iki kere düşünüp ihtiyacınızın bu olduğundan emin olun.
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- State ve Jetpack Compose
- Jetpack Compose için Kotlin
- Compose'da Görünümleri kullanma