---
title: 'Görünüm Modeli'
source: 'https://academia.sh/tr/kurslar/android-mimari/gorunum-modeli'
course: 'Mimari Bileşenler ve Veri Katmanı'
language: tr
updated: '2026-10-21T05:02:37+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Görünüm modelinin yapılandırma değişikliğinde korunduğunu, süreç sonlanmasında kaybolduğunu ayırt eder'
    - 'Ekran döndükten sonra bir okumanın yanıtının bellek basamağından geldiğini ölçer'
    - 'Belleğin sahibinin arayüz olması durumunda aynı okumanın ağa gittiğini gösterir'
    - 'Süreç sonlanmasından sonra aynı okumaların diske, ağa ya da varsayılana düştüğünü sınıflar'
---

# Görünüm Modeli

Görünüm modeli ekran verisini yapılandırma değişikliğinden sağ çıkaracak biçimde tutar, süreç sonlanmasından sağ çıkarmaz. Ders ekran döndüğünde ve süreç sonlandığında bir okumanın kökeninin nasıl değiştiğini ölçer.

Önceki derste okumanın kökenini sınıflayan zinciri kurduk ve belleği elle doldurduk. Platformda belleği dolduran ve ekran döndüğünde onu koruyan bir sahip var: görünüm modeli (ViewModel). Bu derste zincirin ilk basamağına bakıyoruz ve soru aynı kalıyor: **bu okumanın yanıtı nereden geliyor?**

Ölçü aracı önceki dersin çekirdeğidir; değişmeden tekrar veriyoruz.

```kotlin
// 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 }}")
    }
}
```

## Döndürmeden Sağ Çıkan Bellek

Ekran döndüğünde, dil ya da koyu tema değiştiğinde sistem ekranın arayüzünü baştan kurar. Buna yapılandırma değişikliği (configuration change) denir. Arayüz nesneleri yok olur; görünüm modeli yok olmaz. Sistem aynı görünüm modelini yeni arayüze verir. Görünüm modeli ağdan okunan değeri bir alanda tuttuğu için yeni arayüz aynı değeri tekrar ağa gitmeden okur.

```kotlin
// Platform kodu: CartViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

class CartViewModel(private val repository: CartRepository) : ViewModel() {
    var quantity = 1
        private set

    fun load() {
        viewModelScope.launch { quantity = repository.quantity() }
    }
}
```

`quantity` görünüm modelinin alanıdır. `viewModelScope` içindeki iş, görünüm modeli sonlanana kadar sürer; ekranın döndürülmesi bu işi iptal etmez. Bu 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.

Önceki kurslarda ömür eksenleri (M10/K02, M11/K02, M13/K03) bir şeyin ne kadar yaşadığını ölçtü. Bu derste de yaşam süresinden söz ediyoruz, ama ölçü o değil. Bellek bir ömür değil, zincirdeki yerdir: ölçü, okumanın yanıtını bellek basamağının verip vermediğidir.

Model üç işlev ister. `fillMemory` ağdan gelen değerleri bir sahibin belleğine koyar. `surviveRotation` döndürmeden sonra hangi sahiplerin belleğinin kaldığını verir. `afterTermination` süreç sonlandıktan sonra bellekte yalnız kaydedilmiş anahtarları bırakır. Üçü de girdisini dönüştürür.

```kotlin
// Lifecycle.kt — ekran donmesi ve surec sonlanmasi sonrasi hangi bellek kalir
fun fillMemory(store: MutableMap<String, String>, network: Map<String, String>, keys: List<String>): Map<String, String> {
    for (key in keys) network[key]?.let { store[key] = it }
    return store
}

fun surviveRotation(stores: Map<String, Map<String, String>>, keepers: Set<String>): Map<String, String> =
    stores.filterKeys { it in keepers }.values.fold(mapOf()) { all, store -> all + store }

fun afterTermination(memory: Map<String, String>, saved: Set<String>): Map<String, String> =
    memory.filterKeys { it in saved }
```

`surviveRotation` korunanlar kümesindeki sahiplerin belleklerini birleştirir; sahibi korunmayanın belleği yeni arayüze ulaşmaz.

Sepet ekranı görünüm modelinin belleğine adedi ve fiyatı yüklemiş olsun. Ekran döndü. Yeni arayüz beş değeri okuyor.

```kotlin
// Main.kt — ekran dondu, gorunum modeli bellegi korundu
fun main() {
    val network = mapOf("sepet.adet" to "3", "urun.fiyat" to "120", "urun.stok" to "7")
    val disk = mapOf("ayar.tema" to "koyu")
    val stores = mapOf("gorunum-modeli" to fillMemory(mutableMapOf(), network, listOf("sepet.adet", "urun.fiyat")))
    val memory = surviveRotation(stores, setOf("gorunum-modeli"))
    println("kalan bellek anahtarlari: ${memory.keys.sorted()}")

    val chain = listOf(Tier("bellek", memory), Tier("disk", disk), Tier("ag", network))
    val reads = listOf(
        Read("sepet-adedi", "sepet.adet", chain, "0"),
        Read("urun-fiyati", "urun.fiyat", chain, "0"),
        Read("tema", "ayar.tema", chain, "acik"),
        Read("stok", "urun.stok", chain, "0"),
        Read("bildirim", "bildirim.acik", chain, "kapali"),
    )
    reads.forEach { it.show() }
    countOrigins(reads)
}
```

```text
kalan bellek anahtarlari: [sepet.adet, urun.fiyat]
sepet-adedi: anahtar=sepet.adet | deger=3 -> bellek
urun-fiyati: anahtar=urun.fiyat | deger=120 -> bellek
tema: anahtar=ayar.tema | deger=koyu -> disk
stok: anahtar=urun.stok | deger=7 -> ag
bildirim: anahtar=bildirim.acik | deger=kapali -> varsayilan
bellek: 2
disk: 1
ag: 1
varsayilan: 1
```

İki okuma bellekten geldi: adet ve fiyat. Ağa gidilmedi. `stok` hiç yüklenmediği için ağdan, `tema` diskten, `bildirim` varsayılandan geldi.

**UM1.** Model döndürmeyi tek bir olay sayar ve görünüm modelinin hiçbir alanını kaybetmez. Platformda görünüm modelinin kendi alanları da, yanlış yazılırsa, arayüz nesnesine tutunarak sızdırılabilir; modelde bu yok.

## Bellek Kimin

Belleği arayüz nesnesi tutsaydı ne olurdu? Aynı iki değer aynı ekranda aynı ağdan yüklenmiş olurdu, ama sahibi döndürmede yok olurdu. Şimdi iki sahibi yan yana koyalım. Her sahip için aynı yükleme yapılır, aynı döndürme uygulanır ve aynı üç okuma yeniden çalışır.

```kotlin
// Main.kt — ayni yukleme, iki farkli sahip
fun main() {
    val network = mapOf("sepet.adet" to "3", "urun.fiyat" to "120")
    val disk = mapOf("ayar.tema" to "koyu")
    for (owner in listOf("gorunum-modeli", "arayuz")) {
        val stores = mapOf(owner to fillMemory(mutableMapOf(), network, listOf("sepet.adet", "urun.fiyat")))
        val memory = surviveRotation(stores, setOf("gorunum-modeli"))
        val chain = listOf(Tier("bellek", memory), Tier("disk", disk), Tier("ag", network))
        println("sahip: $owner")
        countOrigins(listOf(
            Read("sepet-adedi", "sepet.adet", chain, "0"),
            Read("urun-fiyati", "urun.fiyat", chain, "0"),
            Read("tema", "ayar.tema", chain, "acik"),
        ))
    }
}
```

```text
sahip: gorunum-modeli
bellek: 2
disk: 1
ag: 0
varsayilan: 0
sahip: arayuz
bellek: 0
disk: 1
ag: 2
varsayilan: 0
```

Sahip görünüm modeli olduğunda iki okuma bellekten gelir. Sahip arayüz olduğunda bellek boş kalır ve aynı iki okuma ağa gider; `tema` her iki durumda diskten gelir. Değerler aynı, yükleme aynı, tek fark belleğin döndürmeden sağ çıkıp çıkmadığıdır.

**UM2.** Model korunan sahipleri bir küme olarak alır. Platformda hangi sahibin korunduğunu sistem belirler; kümeyi elle seçmek modelde mümkündür ama platformda değildir.

## Sınırlayıcı Ölçüm

Görünüm modeli yapılandırma değişikliğinden sağ çıkar, süreç sonlanmasından çıkmaz. Sistem bellek açığında uygulamanın arka plandaki sürecini sonlandırabilir; bellekteki her nesne, görünüm modeli dahil, gider. Yalnız kaydedilmiş durum döner. Bu derste hiçbir anahtarı kaydetmedik; kaydedilmiş durum sonraki dersin konusudur. Aynı belleği iki olaydan geçirelim.

```kotlin
// Main.kt — donme ile surec sonlanmasi ayni okumalari farkli kokene tasir
fun main() {
    val network = mapOf("sepet.adet" to "3", "urun.fiyat" to "120")
    val disk = mapOf("ayar.tema" to "koyu")
    val viewModelMemory = fillMemory(mutableMapOf("ekran.sekme" to "ozet"), network, listOf("sepet.adet", "urun.fiyat"))
    val events = listOf(
        "donme" to surviveRotation(mapOf("gorunum-modeli" to viewModelMemory), setOf("gorunum-modeli")),
        "surec-sonlanmasi" to afterTermination(viewModelMemory, emptySet()),
    )
    for ((event, memory) in events) {
        println("olay: $event")
        val chain = listOf(Tier("bellek", memory), Tier("disk", disk), Tier("ag", network))
        val reads = listOf(
            Read("sepet-adedi", "sepet.adet", chain, "0"),
            Read("urun-fiyati", "urun.fiyat", chain, "0"),
            Read("tema", "ayar.tema", chain, "acik"),
            Read("ekran-sekmesi", "ekran.sekme", chain, "ilk"),
        )
        reads.forEach { it.show() }
        countOrigins(reads)
    }
}
```

```text
olay: donme
sepet-adedi: anahtar=sepet.adet | deger=3 -> bellek
urun-fiyati: anahtar=urun.fiyat | deger=120 -> bellek
tema: anahtar=ayar.tema | deger=koyu -> disk
ekran-sekmesi: anahtar=ekran.sekme | deger=ozet -> bellek
bellek: 3
disk: 1
ag: 0
varsayilan: 0
olay: surec-sonlanmasi
sepet-adedi: anahtar=sepet.adet | deger=3 -> ag
urun-fiyati: anahtar=urun.fiyat | deger=120 -> ag
tema: anahtar=ayar.tema | deger=koyu -> disk
ekran-sekmesi: anahtar=ekran.sekme | deger=ilk -> varsayilan
bellek: 0
disk: 1
ag: 2
varsayilan: 1
```

Döndürmede dört okumadan üçü bellekten geldi. Süreç sonlanmasında aynı dört okumanın sonucu değişti: adet ve fiyat ağdan okundu, `tema` diskte kaldı, `ekran-sekmesi` hiçbir basamakta bulunmadığı için varsayılana düştü. Bellekteki sekme seçimi kaydedilmediği için kaybolmuş sayılır.

**UM3.** Model süreç sonlanmasında ağın ulaşılabilir kaldığını varsayar. Platformda bağlantı yoksa adet ve fiyat da varsayılana düşerdi; modelde bu durum kurulmaz.

## Özet

- Bu dersin kökeni: bellek. Ekran döndüğünde görünüm modelinin belleği zincirin ilk basamağıdır ve adet ile fiyat oradan okunur.
- Dersin ölçütü, okumanın yanıtını bellek basamağının verip vermediği. Döndürmeden sonra beş okumada bellek 2, disk 1, ağ 1, varsayılan 1 çıktı.
- Aynı yükleme için belleğin sahibi görünüm modeli olunca bellek 2, ağ 0; sahibi arayüz olunca bellek 0, ağ 2 çıktı.
- Süreç sonlanmasında bellek boşalır: dört okumada bellek 3'ten 0'a düştü, ağ 0'dan 2'ye, varsayılan 0'dan 1'e çıktı.
- Kaydedilmemiş sekme seçimi varsayılana düştü; kaydedilmiş durum sonraki dersin konusudur.

## Sonraki Adım

Bu derste kaydedilen anahtar kümesi boştu ve sekme seçimi kayboldu. Sıradaki ders, `Durum Tutucular`, ekranın durumunu tek bir yerde toplayıp kaydedilen alanı diskten nasıl geri yüklediğini ölçer.
