Ders 04 / 14
Gözlemlenebilir Durum
Gözlemlenebilir durum, değeri değiştikçe toplayıcılara yeni değer yayan bir durum akışıdır; akışın her zaman bir ilk değeri vardır. Ders bir toplayıcının yükleme bitmeden ve bittikten sonra okuduğu değerin kökenini ölçer.
Yayın Güncelleme
Bu derste
- Gözlemlenebilir durumun ilk değerle başladığını ve toplayıcıya değişiklikleri yayınladığını açıklar
- Yükleme bitmeden toplayıcının okuduğu değerin varsayılandan geldiğini ölçer
- Yavaş toplayıcının ara değeri görmediğini ama son değerin kökenini değiştirmediğini gösterir
- Aynı akışın yükleme sürerken ve bitince iki farklı kökenden yanıt verdiğini sınıflar
İçindekiler
Önceki derste durum tutucunun alanları süreç sonlandıktan sonra geri geldi, ama tutucu yüklemenin bitip bitmediğini söylemedi. Arayüz değeri nasıl öğrenir? Değer değiştikçe haber veren bir yapı kullanır: gözlemlenebilir durum (observable state). Soru aynı: bu okumanın yanıtı nereden geliyor?
Ölçü aracı önceki derslerin çekirdeğidir; değişmeden tekrar veriyoruz.
// Origin.kt — bir okumanin yanitinin hangi basamaktan geldigini siniflandirir
class Tier(val origin: String, private val entries: Map<String, String>) {
init {
require(origin in listOf("bellek", "disk", "ag")) { "gecersiz basamak: $origin" }
}
fun lookup(key: String): String? = entries[key]
}
class Read(val label: String, val key: String, chain: List<Tier>, fallback: String) {
private val hit: Tier? = chain.firstOrNull { it.lookup(key) != null }
val value: String = hit?.lookup(key) ?: fallback
val origin: String = hit?.origin ?: "varsayilan"
fun show() {
println("$label: anahtar=$key | deger=$value -> $origin")
}
}
fun countOrigins(reads: List<Read>) {
for (name in listOf("bellek", "disk", "ag", "varsayilan")) {
println("$name: ${reads.count { it.origin == name }}")
}
}
Akışın İlk Değeri
Platformda gözlemlenebilir durum çoğunlukla bir durum akışıdır (StateFlow). Akış her zaman bir değer taşır: kurulurken verilen ilk değer. Durumu değiştiren taraf yeni değeri akışa yazar; değeri okuyan taraf, yani toplayıcı, akışı toplar (collect) ve her yeni değeri alır. Toplama bir eş yordamda koşar; akış başka bir kaynaktan türüyorsa stateIn ile durum akışına çevrilir ve çoğunlukla bir ilk değer verilerek kurulur.
// Platform kodu: CartViewModel
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class CartViewModel : ViewModel() {
private val _state = MutableStateFlow(CartUiState())
val state: StateFlow<CartUiState> = _state
fun onLoaded(items: List<CartItem>) {
_state.value = CartUiState(items)
}
}
Arayüz akışı toplar ve her değerde yeniden çizilir.
// Platform kodu: CartScreen
import androidx.compose.runtime.getValue
@Composable
fun CartScreen(viewModel: CartViewModel) {
val state by viewModel.state.collectAsState()
Text("Urun: ${state.items.size}")
}
CartUiState() akışın ilk değeridir: sepet henüz yüklenmemiştir ve liste boştur. Bu iki parça platform kodudur ve burada çıktı, süre ya da dosya yolu iddia etmiyoruz. Model, platformun bu kuralını kurar; model platformun kendisi değildir.
Modelde akışı düz bir liste olarak kuruyoruz: ilk değer listenin ilk elemanıdır, her yayın önceki son değerin üstüne yazılan yeni bir değer ekler. latest son değeri, fastCollector her yayını, slowCollector yalnız son yayını verir. collectReads bir toplayıcının dört okumasını kurar; toplayıcının zincirinde akıştan başka basamak yoktur.
// Feed.kt — gozlemlenebilir durum: ilk deger vardir, her yayin listeye eklenir
class Feed(initial: Map<String, String>) {
private val emitted = mutableListOf(initial)
fun emit(update: Map<String, String>) {
emitted.add(emitted.last() + update)
}
fun latest(): Map<String, String> = emitted.last()
fun fastCollector(): List<Map<String, String>> = emitted.toList()
fun slowCollector(): List<Map<String, String>> = listOf(emitted.last())
}
fun collectReads(value: Map<String, String>): List<Read> {
val chain = listOf(Tier("bellek", value))
return listOf(
Read("baslik", "ekran.baslik", chain, "bos"),
Read("urun-fiyati", "urun.fiyat", chain, "0"),
Read("stok", "urun.stok", chain, "0"),
Read("kampanya", "kampanya.kod", chain, "yok"),
)
}
Yükleme başlamadan toplayıcı akışı toplar. Akışın ilk değerinde yalnız ekran başlığı var.
// Main.kt — toplayicinin ilk okumasi yukleme bitmeden yapilir
fun main() {
val feed = Feed(mapOf("ekran.baslik" to "Sepet"))
val reads = collectReads(feed.latest())
reads.forEach { it.show() }
countOrigins(reads)
}
baslik: anahtar=ekran.baslik | deger=Sepet -> bellek urun-fiyati: anahtar=urun.fiyat | deger=0 -> varsayilan stok: anahtar=urun.stok | deger=0 -> varsayilan kampanya: anahtar=kampanya.kod | deger=yok -> varsayilan bellek: 1 disk: 0 ag: 0 varsayilan: 3
Başlık akışın ilk değerinde olduğu için bellekten geldi. Fiyat, stok ve kampanya yüklenmediği için akışta yok: üç okuma varsayılana düştü. Ağ yanıtı yolda; yanıt vermemiş bir basamak toplayıcının zincirinde değildir.
UM1. Model akışı düz liste olarak kurar ve toplayıcının zincirine yalnız akışı koyar. Platformda yükleme aynı anda disk ya da ağdan da başlayabilir; toplayıcı yine yalnız akışa bakar.
Yavaş Toplayıcı
Akış iki yayın yapsın: önce eski bir fiyat, sonra yeni fiyat. Her yayını gören toplayıcıya hızlı, yalnız sonuncuyu gören toplayıcıya yavaş diyelim. Durum akışı değeri birleştirdiği için yavaş toplayıcı ara değeri hiç görmez.
// Main.kt — yavas toplayici ara degeri gormez
fun main() {
val feed = Feed(mapOf("ekran.baslik" to "Sepet"))
feed.emit(mapOf("urun.fiyat" to "100"))
feed.emit(mapOf("urun.fiyat" to "120"))
println("hizli toplayici:")
for (value in feed.fastCollector()) {
println(" fiyat=${value["urun.fiyat"] ?: "yok"}")
}
println("yavas toplayici:")
for (value in feed.slowCollector()) {
println(" fiyat=${value["urun.fiyat"] ?: "yok"}")
}
countOrigins(collectReads(feed.latest()))
}
hizli toplayici: fiyat=yok fiyat=100 fiyat=120 yavas toplayici: fiyat=120 bellek: 2 disk: 0 ag: 0 varsayilan: 2
Hızlı toplayıcı üç değer gördü: fiyat yok, 100, 120. Yavaş toplayıcı yalnız 120’yi gördü. İki toplayıcı da sonunda aynı değeri okudu ve o değerin kökeni aynı: akışın içindeki her değer bellektir. Son değerle yapılan dört okumada iki bellek, iki varsayılan çıktı.
UM2. Model yavaşlığı iki sabit toplayıcı türüyle kurar. Platformda toplayıcının yavaşlığı zamanlamaya bağlıdır ve modelde zaman yoktur.
Sınırlayıcı Ölçüm
Aynı akışı iki anda okuyalım: yükleme sürerken ve yükleme bitince. Yükleme bitince fiyat ve stok akışa yazılır; yani anahtarlar belleğe girer.
// Main.kt — ayni akis iki anda iki koken verir
fun main() {
val feed = Feed(mapOf("ekran.baslik" to "Sepet"))
println("yukleme: surerken")
countOrigins(collectReads(feed.latest()))
feed.emit(mapOf("urun.fiyat" to "120", "urun.stok" to "7"))
println("yukleme: bitince")
val after = collectReads(feed.latest())
after.forEach { it.show() }
countOrigins(after)
}
yukleme: surerken bellek: 1 disk: 0 ag: 0 varsayilan: 3 yukleme: bitince baslik: anahtar=ekran.baslik | deger=Sepet -> bellek urun-fiyati: anahtar=urun.fiyat | deger=120 -> bellek stok: anahtar=urun.stok | deger=7 -> bellek kampanya: anahtar=kampanya.kod | deger=yok -> varsayilan bellek: 3 disk: 0 ag: 0 varsayilan: 1
Yükleme sürerken bir okuma bellek, üç okuma varsayılan verdi. Yükleme bitince fiyat ve stok akışa girdi: bellek üçe çıktı, varsayılan bire indi. Aynı akış, aynı toplayıcı, aynı dört okuma; değişen tek şey akışın hangi anda okunduğu. kampanya yükleme bitse de akışa girmediği için varsayılan kalır.
UM3. Model yüklemenin bittiğini tek bir yayınla işaretler. Platformda yükleme parça parça biter ve her parça ayrı bir yayın olabilir; modelde bu ayrım yok.
Özet
- Bu dersin kökeni: varsayılan. Toplayıcı yükleme bitmeden okuduğunda fiyat, stok ve kampanya akışta olmadığı için okumaların kendi varsayılanları yanıt oldu.
- Dersin ölçütü, toplayıcının okuduğu değerin akışın hangi anındaki değerden geldiği. Yükleme sürerken bellek 1, varsayılan 3; bitince bellek 3, varsayılan 1 çıktı.
- Akışın ilk değeri bir yanıttır: ekran başlığı bellekten geldi, çünkü ilk değerde vardı.
- Yavaş toplayıcı ara değer olan 100’ü görmedi, yalnız 120’yi gördü; akıştaki her değerin kökeni bellektir.
- Akışın zincirinde yanıt vermemiş bir basamak yoktur; toplayıcı yalnız akışı görür.
Sonraki Adım
Bu derste akış yüklemeyi dışarıdan alıp yayınladı. Olayın akışı nasıl değiştirdiği ayrı bir sorudur. Sıradaki ders, Tek Yönlü Veri Akışı, bir olayın durumu bellekte nasıl yeniden kurduğunu ve değerin arayüzden yukarı değil aşağı gittiğini ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.