---
title: 'Kaynak Sistemi'
source: 'https://academia.sh/tr/kurslar/android-platformu/kaynak-sistemi'
course: 'Android Platformu ve Araçlar'
language: tr
updated: '2026-10-21T05:02:36+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Kaynak türlerini ve kaynak kimliğinin koddan nasıl kullanıldığını açıklar'
    - 'Niteleyicili dizinde tam eşleşmenin tam, varsayılan dizine düşmenin ikame olduğunu ölçer'
    - 'Varsayılan dizinde de bulunmayan kaynağın karşılıksız kaldığını gösterir'
    - 'İki niteleyici çakıştığında önceliğin sonucu belirlediğini sınırlayıcı ölçümle doğrular'
---

# Kaynak Sistemi

Kaynak kimliğinin yapılandırmaya göre niteleyicili dizinlerden seçilmesinin, tam eşleşmenin, varsayılana düşmenin ve niteleyici önceliğinin modeli.

Önceki ders bildirim dosyasının birleştirmesini, her öğeyi ayrı bir istek sayarak ölçtü. Bildirim dosyası uygulamanın ne olduğunu bildirir; ekranda görünen metin, görsel ve düzen ise kaynaklarda durur. Kaynaklar kodun içine gömülmez, ayrı dosyalarda tutulur, çünkü aynı kaynak aygıtın diline, ekran boyutuna ve gece ya da gündüz görünümüne göre farklı bir dosyadan gelmelidir. Bu ders kaynak sisteminin istenen yapılandırma için bir kaynak seçerken ne verdiğini ölçer.

Kursun ölçü ekseni değişmez: bu isteği platform nasıl karşılıyor. Karşılama dörttür: tam, ikame, bekleyen ve karşılıksız. Karşılamayı etiket değil kural verir: verilen değer istenene eşitse tam, eşit değilse ikame; bekleyen ve karşılıksız doğrudan sonuçtan çıkar. Aşağıdaki dosya o kuralı taşır ve her derste aynen yinelenir. Açılış dersindeki 3/2/2/1 sayısı burada değiştirilmez.

```kotlin
// Fulfillment.kt — bir istegin platformca nasil karsilandigini siniflandirir
sealed interface Outcome {
    data class Given(val value: String) : Outcome
    data class Waiting(val on: String) : Outcome
    data class Refused(val reason: String) : Outcome
}

class Ask(val label: String, val wanted: String, val outcome: Outcome) {
    val fulfillment: String = when (outcome) {
        is Outcome.Waiting -> "bekleyen"
        is Outcome.Refused -> "karsiliksiz"
        is Outcome.Given -> if (outcome.value == wanted) "tam" else "ikame"
    }

    fun report() {
        val detail = when (outcome) {
            is Outcome.Given -> "verilen=${outcome.value}"
            is Outcome.Waiting -> "bekledigi=${outcome.on}"
            is Outcome.Refused -> "neden=${outcome.reason}"
        }
        println("$label: istenen=$wanted | $detail -> $fulfillment")
    }
}

fun tally(asks: List<Ask>) {
    for (name in listOf("tam", "ikame", "bekleyen", "karsiliksiz")) {
        println("$name: ${asks.count { it.fulfillment == name }}")
    }
}
```

## Kaynak Türleri ve Kaynak Kimliği

Kaynaklar `res` dizininin altında türe göre ayrılmış alt dizinlerde durur. Metinler `values` dizinindeki XML dosyalarındadır; çizilebilir görseller `drawable` dizinindedir; ekran düzenleri `layout` dizinindedir. Her kaynağın bir adı vardır ve derleme adımı bu adlardan kaynak kimliği (resource ID) üretir: koddan `R.string.title` ya da `R.drawable.logo` yazılarak ulaşılır. Kod hangi dosyadan okunacağını bilmez, yalnız kimliği bilir; dosyayı seçmek sistemin işidir.

```xml
<resources>
    <string name="title">Notes</string>
    <string name="subtitle">Everything in one place</string>
</resources>
```

Bu parça varsayılan `values` dizinindeki metin dosyasıdır. Almanca için aynı adlarla ayrı bir dosya `values-de` dizinine konabilir ve yalnız `title` kimliğini içerebilir. Dizin adındaki `-de` kısmına niteleyici (qualifier) denir. Aşağıdaki parça koddan kimlikle okumayı gösterir.

```kotlin
// Platform kodu: kimlikle metin okuma
val heading = getString(R.string.title)
```

Platform kodudur ve çalıştırılmaz. Sistem bu satırda, aygıtın o andaki yapılandırmasına uyan dizini seçer; model, platformun bu kuralını kurar. Niteleyiciler dil, bölge, gece görünümü ve en küçük ekran genişliği gibi bir yapılandırma özelliğini adlandırır: `values-de`, `values-de-rAT`, `values-night`, `layout-sw600dp`.

## Seçim Modeli

Model beş şey bilir: kaynak anahtarı, istenen dizin adı, aygıtın yapılandırması ve dizinler. İstenen, yapılandırmanın tam adlandırdığı dizindir. Bir dizin yalnız anahtarı içeriyorsa ve niteleyicilerinin hepsi yapılandırmada varsa aday olur. Adaylar arasından önceliği en yüksek niteleyiciye sahip olan seçilir; öncelik sırası dil, bölge, ekran genişliği, gece görünümüdür. Varsayılan dizinin niteleyicisi yoktur, bu yüzden anahtarı içeriyorsa her zaman adaydır. Aday yoksa kaynak bulunamaz.

```kotlin
// Resources.kt — kaynak secimi modeli
class ResourceDir(val name: String, val keys: Set<String>) {
    val tokens: List<String> = name.split("-").drop(1)
}

fun qualifierWeight(token: String): Int = when {
    token == "night" -> 1
    token.startsWith("sw") -> 2
    token.length == 3 && token.startsWith("r") -> 4
    else -> 8
}

fun resolveResource(key: String, wanted: String, config: Set<String>, dirs: List<ResourceDir>): Ask {
    val candidates = dirs.filter { key in it.keys && it.tokens.all { token -> token in config } }
    val best = candidates.maxByOrNull { dir -> dir.tokens.sumOf { qualifierWeight(it) } }
    val outcome = if (best == null) Outcome.Refused("varsayilan-yok") else Outcome.Given(best.name)
    return Ask(key, wanted, outcome)
}
```

Ağırlıklar öncelik sırasını kurar: dil ağırlığı sekiz, bölge dört, genişlik iki, gece birdir. Bir üst niteleyicinin ağırlığı altındakilerin toplamından büyüktür; bu yüzden dil, ne kadar genişlik ve gece niteleyicisi olursa olsun önce gelir. İlk ölçüm üç kaynak ister. Metin anahtarı Almanca dizinde vardır ve yapılandırma Almancadır. Görsel gece dizininde vardır ve yapılandırma geceyi içerir. Alt başlık metni ise yalnız varsayılan dizinde bulunur; Almanca dizin onu içermez.

```kotlin
// Main.kt — tam eslesme ve varsayilana dusme
fun main() {
    val dirs = listOf(
        ResourceDir("values", setOf("string/title", "string/subtitle")),
        ResourceDir("values-de", setOf("string/title")),
        ResourceDir("drawable", setOf("drawable/logo")),
        ResourceDir("drawable-night", setOf("drawable/logo")),
    )
    val config = setOf("de", "night")
    val asks = listOf(
        resolveResource("string/title", "values-de", config, dirs),
        resolveResource("drawable/logo", "drawable-night", config, dirs),
        resolveResource("string/subtitle", "values-de", config, dirs),
    )
    for (ask in asks) ask.report()
    tally(asks)
}
```

```text
string/title: istenen=values-de | verilen=values-de -> tam
drawable/logo: istenen=drawable-night | verilen=drawable-night -> tam
string/subtitle: istenen=values-de | verilen=values -> ikame
tam: 2
ikame: 1
bekleyen: 0
karsiliksiz: 0
```

İlk iki kimlik tam eşleşen dizinden geldi. Alt başlık için istenen dizin Almancaydı ama orada yoktu; sistem varsayılan dizindeki metni verdi. Bu ikamedir ve uygulama çökmedi: varsayılan dizin bir güvenlik ağıdır.

**AP1.** Model dört niteleyici türünü bilir ve her dizinde bu türlerden en çok birer tane bekler. Gerçek niteleyici kümesi çok daha geniştir ve her türün kendi eşleşme kuralı vardır.

**AP2.** Model, bir niteleyicinin yapılandırmada bulunmasını yeterli sayar. Ekran genişliği gibi sayısal niteleyicilerde gerçek sistem eşitlik değil eşik karşılaştırır; bu ölçümde `sw600dp` yalnız bir ad olarak ele alınır.

## Yapılandırma Değişikliği

Aygıt döndürüldüğünde ya da gece görünümü açıldığında yapılandırma değişir ve activity yeniden kurulur; kaynaklar yeni yapılandırmaya göre yeniden seçilir. Aşağıdaki ölçüm aynı anahtarı iki yapılandırmada sorar. Dizinler `values`, `values-de` ve `values-night`'tır. Almanca yapılandırmada `values-de` seçilir. Gece eklenince hem `values-de` hem `values-night` aday olur; istenen ise ikisinin birleşimini adlandıran `values-de-night`'tır. Üçüncü satır yalnız Almanca dizinde olan bir anahtarı Fransızca yapılandırmada sorar.

```kotlin
// Main.kt — yapilandirma degisince yeniden secim
fun main() {
    val dirs = listOf(
        ResourceDir("values", setOf("string/title")),
        ResourceDir("values-de", setOf("string/title", "string/promo")),
        ResourceDir("values-night", setOf("string/title")),
    )
    val asks = listOf(
        resolveResource("string/title", "values-de", setOf("de"), dirs),
        resolveResource("string/title", "values-de-night", setOf("de", "night"), dirs),
        resolveResource("string/promo", "values-fr", setOf("fr"), dirs),
    )
    for (ask in asks) ask.report()
    tally(asks)
}
```

```text
string/title: istenen=values-de | verilen=values-de -> tam
string/title: istenen=values-de-night | verilen=values-de -> ikame
string/promo: istenen=values-fr | neden=varsayilan-yok -> karsiliksiz
tam: 1
ikame: 1
bekleyen: 0
karsiliksiz: 1
```

Aynı kimlik yapılandırma değişince tamdan ikameye geçti: ikinci yapılandırmanın adlandırdığı birleşik dizin yoktu. Üçüncü kimlik karşılıksızdır, çünkü `string/promo` yalnız Almanca dizinde vardı ve varsayılan dizinde bulunmuyordu; Fransızca yapılandırmada aday kalmadı. Gerçek sistemin bu durumda tam olarak ne yaptığı bu derste iddia edilmez; model yalnız karşılığın verilmediğini sınıflar.

Yapılandırma ölçünün girdisidir; ama sonucu belirleyen girdi değildir. Aynı yapılandırma bir kimlikte tam, ötekinde ikame verir. Sonucu belirleyen, verilen dizinin istenen dizine eşit olup olmadığıdır.

## Tür Dizinleri ve Ekran Genişliği

Kaynak dizinleri türe göre adlandırılır. `values` metin, renk ve ölçü gibi basit değerleri, `drawable` görselleri, `layout` ekran düzenlerini taşır. Her türün dizini kendi niteleyicilerini alabilir. Ekran genişliği niteleyicisi `sw600dp` gibi yazılır ve en küçük kenar uzunluğunun o değerden az olmadığı aygıtlarda geçerlidir. Aşağıdaki parça geniş ekranlar için ayrı bir düzen dizinini gösterir.

```xml
<!-- layout-sw600dp/main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```

Aynı ad `layout` dizininde de bulunabilir; geniş ekranda `layout-sw600dp` dizinindeki seçilir, dar ekranda varsayılan dizindeki. İstenen yine yapılandırmanın tam adlandırdığı dizindir. Ölçümde yapılandırma bir tablet gibi geniş ve Almanca. Üç tür ister: düzen, metin ve görsel. Düzen yalnız geniş ekran dizininde ve varsayılanda vardır. Metin yalnız Almanca dizinde ve varsayılanda vardır. Görsel yalnız varsayılan dizindedir.

```kotlin
// Main.kt — kaynak turleri
fun main() {
    val dirs = listOf(
        ResourceDir("layout", setOf("layout/main")),
        ResourceDir("layout-sw600dp", setOf("layout/main")),
        ResourceDir("values", setOf("string/title")),
        ResourceDir("values-de", setOf("string/title")),
        ResourceDir("drawable", setOf("drawable/logo")),
    )
    val config = setOf("de", "sw600dp")
    val asks = listOf(
        resolveResource("layout/main", "layout-sw600dp", config, dirs),
        resolveResource("string/title", "values-de", config, dirs),
        resolveResource("drawable/logo", "drawable-sw600dp", config, dirs),
    )
    for (ask in asks) ask.report()
    tally(asks)
}
```

```text
layout/main: istenen=layout-sw600dp | verilen=layout-sw600dp -> tam
string/title: istenen=values-de | verilen=values-de -> tam
drawable/logo: istenen=drawable-sw600dp | verilen=drawable -> ikame
tam: 2
ikame: 1
bekleyen: 0
karsiliksiz: 0
```

İlk iki istek yapılandırmanın adlandırdığı dizinden karşılandı. Üçüncüsü geniş ekrana özel bir görsel istedi ama yalnız varsayılan görsel vardı; varsayılan verildi ve ikame oldu.

**AP3.** Model yalnız `de`, `rAT`, `night` ve `sw` niteleyicilerini tanır. Gerçek sistemde yoğunluk, yön ve platform sürümü gibi başka niteleyiciler de vardır; ölçüm bunları kapsamaz.

## Elemenin Adımları

Seçim iki adımda yapılır. Önce yapılandırmayla çelişen dizinler elenir: bir niteleyicisi yapılandırmada olmayan dizin aday olamaz. Sonra kalan adaylar arasından niteleyici öncelik sırasına göre en iyisi seçilir. Birinci adımda `values-night` gündüz yapılandırmasında elenir, `values-de` ise Almanca yapılandırmada kalır. Aday listesi boşsa kaynak bulunamaz. Varsayılan dizinde de yoksa bu, kaynağın hiçbir yerde tanımlanmadığı anlamına gelir. Ölçümde yapılandırma gündüz ve Almanca. Gece dizini ve Almanca dizini vardır; ayrıca hiçbir dizinde olmayan bir anahtar sorulur.

```kotlin
// Main.kt — elenen dizin ve eksik anahtar
fun main() {
    val dirs = listOf(
        ResourceDir("values", setOf("string/title")),
        ResourceDir("values-night", setOf("string/title")),
        ResourceDir("values-de", setOf("string/title")),
    )
    val config = setOf("de")
    val asks = listOf(
        resolveResource("string/title", "values-night", config, dirs),
        resolveResource("string/title", "values-de", config, dirs),
        resolveResource("string/missing", "values", config, dirs),
    )
    for (ask in asks) ask.report()
    tally(asks)
}
```

```text
string/title: istenen=values-night | verilen=values-de -> ikame
string/title: istenen=values-de | verilen=values-de -> tam
string/missing: istenen=values | neden=varsayilan-yok -> karsiliksiz
tam: 1
ikame: 1
bekleyen: 0
karsiliksiz: 1
```

Gece dizini istendiği halde gündüz yapılandırmasında elendi ve Almanca dizin verildi: ikame. Hiçbir dizinde olmayan anahtar karşılıksız kaldı; neden `varsayilan-yok` olarak adlandırılır, çünkü model varsayılan dizinde de bulamamıştır.

**AP4.** Model elemeyi niteleyicinin yapılandırmada bulunup bulunmadığına bakarak yapar. Gerçek sistem niteleyicileri öncelik sırasıyla tek tek eleyerek ilerler; ikisi çoğu durumda aynı sonucu verir ama ölçüm bunu karşılaştırmaz.

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

Model niteleyicileri tek tek eşleştirir; bir niteleyicinin yakın bir başkasıyla örtüşmesini bilmez. Almanca konuşulan her bölge için ayrı bir `values-de-rAT` gibi dizin yazılabilir. Bölge dizini yoksa ve yalnız `values-de` varsa, Avusturya bölgesi yapılandırması Almanca dizinden okur: model bunu ikame olarak sınıflar. İkinci ve üçüncü satır iki niteleyicinin çakışmasını sınar. Dizinler `values-de` ve `values-night`'tır, yapılandırma ikisini de içerir. Önce ikisi de varken, sonra Almanca dizin çıkarılınca sorulur.

```kotlin
// Main.kt — bolge ve oncelik
fun main() {
    val region = listOf(
        ResourceDir("values", setOf("string/title")),
        ResourceDir("values-de", setOf("string/title")),
    )
    val both = listOf(
        ResourceDir("values-de", setOf("string/title")),
        ResourceDir("values-night", setOf("string/title")),
        ResourceDir("values", setOf("string/title")),
    )
    val nightOnly = both.filter { it.name != "values-de" }
    val config = setOf("de", "rAT", "night")
    val asks = listOf(
        resolveResource("string/title", "values-de-rAT", config, region),
        resolveResource("string/title", "values-de-night", config, both),
        resolveResource("string/title", "values-de-night", config, nightOnly),
    )
    for (ask in asks) ask.report()
    tally(asks)
}
```

```text
string/title: istenen=values-de-rAT | verilen=values-de -> ikame
string/title: istenen=values-de-night | verilen=values-de -> ikame
string/title: istenen=values-de-night | verilen=values-night -> ikame
tam: 0
ikame: 3
bekleyen: 0
karsiliksiz: 0
```

Üç satır da ikamedir ve kural aralarını ayırmaz: üçünde de verilen istenenden farklıdır. Ayrımı verilen sütunu gösterir. İkinci satırda iki aday varken dil kazandı. Üçüncü satırda dil dizini kalmadığı için gece dizini seçildi. Öncelik sırasını model kurar; kural yalnız sonucu görür, o sonucun neden seçildiğini görmez. Sayım üç ikameyi sayar ve önceliğin işlediğini göstermez.

**AP5.** Model önceliği dil, bölge, genişlik, gece biçiminde kurar; bu dört niteleyici platformun listesinde de bu sıradadır. Platformun tam öncelik listesi daha uzundur ve ağırlık toplamı kullanmaz, niteleyicileri sırayla eler. Ölçüm yalnız bu dört niteleyici için sıranın çalıştığını gösterir.

## Özet

- Bu dersin ölçütü: **karşılama**; verilen dizinin istenen dizine eşit olup olmadığı, yapılandırmanın kendisi değil. Bu dersin karşılaması: **ikame**.
- Kaynaklar `res` altında türe göre dizinlerde durur; koddan kaynak kimliğiyle ulaşılır ve dosyayı sistem seçer.
- Niteleyiciler dizin adının sonundaki yapılandırma özellikleridir: dil, bölge, gece görünümü, ekran genişliği.
- Yapılandırmanın adlandırdığı dizin varsa kaynak tam, yoksa varsayılan dizinden gelen kaynak ikamedir.
- Varsayılan dizinde de bulunmayan kaynak karşılıksızdır.
- İki niteleyici çakışınca öncelik sırası sonucu belirler; kural bu nedeni görmez, yalnız verilenle istenenin eşitliğini görür.

## Sonraki Adım

Kaynaklar ve bildirim dosyası bir araya gelip çalıştırılabilir bir uygulamaya dönüşmek için derlenmelidir. Sonraki ders derleme sistemini ele alır ve bağımlılıkların sürümleri çakıştığında hangi sürümün verildiğini ölçer.
