---
title: 'Arka Plan İşleri'
source: 'https://academia.sh/tr/kurslar/android-mimari/arka-plan-isleri'
course: 'Mimari Bileşenler ve Veri Katmanı'
language: tr
updated: '2026-10-21T05:02:37+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Ertelenebilir işi ve kısıtı, işin hangi koşulda çalışacağını söyleyen kurallar olarak açıklar'
    - 'Kısıt sağlanınca diske yazan işten sonra okumanın kökenini disk olarak ölçer'
    - 'Tek seferlik ile dönemsel işi, işin kaç kez çalıştığı üzerinden karşılaştırır'
    - 'Kısıt sağlanmayınca işin çalışmadığını ve okumanın varsayılana ya da eski diske düştüğünü gösterir'
---

# Arka Plan İşleri

Ertelenebilir bir iş, kısıtları sağlandığında ağdan çekip diske yazar ve ekranın sonraki okuması diskten gelir. Ders kısıt sağlanınca okumanın kökenini, kısıt sağlanmayınca okumanın neye düştüğünü ve kursun on dört dersinin köken dağılımını ölçer.

Önceki derste sayfalar kullanıcı indikçe ve uygulama açıkken yüklendi. Bazı veri ise kullanıcı ekrana bakmazken de yenilenmelidir: ağın uygun olduğu bir anda, şarj sırasında ya da uygulama kapalıyken. Bu derste yenilemeyi ekranın değil, ertelenebilir bir işin yaptığını varsayıyoruz. Dersin sorusu önceki derslerle aynıdır: **bu okumanın yanıtı nereden geliyor?**

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

## Ertelenebilir İş ve Kısıt

Arka plan işi (background work), kullanıcının bir ekranda beklemediği ve hemen bitmesi gerekmeyen iştir. Böyle bir iş ertelenebilir (deferrable) olduğu için sistem onu uygun bir ana bırakabilir. İşin ne zaman çalışabileceğini kısıtlar (constraints) söyler: ağa bağlı olmak, şarjda olmak gibi. Kısıtların hepsi sağlanmadıkça iş çalışmaz; sağlandıktan sonra işi ne zaman çalıştıracağına sistem karar verir.

```kotlin
// Platform kodu: RefreshWorker ve istekler
class RefreshWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result = try {
        repository.refresh()
        Result.success()
    } catch (e: IOException) {
        Result.retry()
    }
}

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .setRequiresCharging(true)
    .build()
val once = OneTimeWorkRequestBuilder<RefreshWorker>().setConstraints(constraints).build()
val periodic = PeriodicWorkRequestBuilder<RefreshWorker>(1, TimeUnit.DAYS).setConstraints(constraints).build()
```

Bu parça platform kodudur ve burada çıktı, süre ya da çalışma sayısı iddia etmiyoruz. `doWork` önceki derslerdeki `refresh` işlevini çağırır; ağ yoksa işi daha sonra yeniden denemesini ister. `Constraints` ağ bağlantısını ve şarjı koşul koyar. İstek tek seferlik ya da dönemsel kurulabilir. Model, platformun bu kuralını kurar; model platformun kendisi değildir.

## Modelde İş

Modelde iş, bir işlevdir. Gereken kısıtların hepsi sağlanmışsa ağdan istenen anahtarları alıp diske yazar, sağlanmamışsa diski olduğu gibi bırakır. Ekran önceki derste olduğu gibi yalnız diski okur.

```kotlin
// Work.kt — kisitlarin hepsi saglandiysa istenen anahtarlari diske yazar, saglanmadiysa diski birakir
fun runWork(
    required: Set<String>,
    satisfied: Set<String>,
    disk: Map<String, String>,
    network: Tier,
    keys: List<String>,
): Map<String, String> {
    if (!satisfied.containsAll(required)) return disk
    return disk + keys.mapNotNull { key -> network.lookup(key)?.let { key to it } }
}
```

```kotlin
// Screen.kt — ana ekran yalniz diski okur
fun readHomeScreen(disk: Map<String, String>): List<Read> {
    val chain = listOf(Tier("disk", disk))
    return listOf(
        Read("fiyat", "urun.fiyat", chain, "bilinmiyor"),
        Read("stok", "urun.stok", chain, "0"),
        Read("kampanya", "kampanya.kod", chain, "yok"),
    )
}
```

## Kısıt Sağlanınca Diske Yazar

Disk boş. İş iki kısıt ister: `ag-bagli` ve `sarjda`. İkisi de sağlanıyor ve sunucu üç anahtarı da biliyor.

```kotlin
// Main.kt — kisitlar saglaninca is ag degerlerini diske yazar, sonraki okuma diskten gelir
fun main() {
    val required = setOf("ag-bagli", "sarjda")
    val network = Tier("ag", mapOf("urun.fiyat" to "125", "urun.stok" to "8", "kampanya.kod" to "YAZ10"))
    val keys = listOf("urun.fiyat", "urun.stok", "kampanya.kod")
    println("is calismadan once")
    readHomeScreen(emptyMap()).forEach { it.show() }
    val disk = runWork(required, required, emptyMap(), network, keys)
    println("is calistiktan sonra")
    val reads = readHomeScreen(disk)
    reads.forEach { it.show() }
    countOrigins(reads)
}
```

```text
is calismadan once
fiyat: anahtar=urun.fiyat | deger=bilinmiyor -> varsayilan
stok: anahtar=urun.stok | deger=0 -> varsayilan
kampanya: anahtar=kampanya.kod | deger=yok -> varsayilan
is calistiktan sonra
fiyat: anahtar=urun.fiyat | deger=125 -> disk
stok: anahtar=urun.stok | deger=8 -> disk
kampanya: anahtar=kampanya.kod | deger=YAZ10 -> disk
bellek: 0
disk: 3
ag: 0
varsayilan: 0
```

İş çalışmadan önce üç okumanın üçü varsayılandı. İş çalıştıktan sonra aynı üç okuma diskten geldi. Okumanın zincirine ağ girmedi: ağ yalnız diski doldurdu, ekran diskten okudu. Bu dersin kökeni disktir. Yenilemeyi ekran açılırken değil, ekran açılmadan önce bir iş yaptı.

**VK3.** Model, kısıtların sağlandığı anı verilmiş bir küme olarak alır ve işi o anda tek adımda çalıştırır. Platformda sistemin işi ne zaman başlattığı, işin yarıda kesilmesi ve aynı işin iki kez kuyruğa girmesi modelde yoktur.

## Tek Seferlik ve Dönemsel İş

Tek seferlik iş bir kez çalışır. Dönemsel iş her dönemde yeniden çalışır. İkisinin ekranın okumasına etkisi, sunucu değeri değiştiğinde ayrılır. Disk 120 ve 9 ile başlıyor; sunucu önce 125 ve 8, sonra 130 ve 6 söylüyor.

```kotlin
// Main.kt — tek seferlik is bir kez, donemsel is her donemde diski yeniler
fun main() {
    val required = setOf("ag-bagli")
    val start = mapOf("urun.fiyat" to "120", "urun.stok" to "9")
    val first = Tier("ag", mapOf("urun.fiyat" to "125", "urun.stok" to "8"))
    val second = Tier("ag", mapOf("urun.fiyat" to "130", "urun.stok" to "6"))
    val keys = listOf("urun.fiyat", "urun.stok")
    val afterFirst = runWork(required, required, start, first, keys)
    println("tek seferlik: ilk calisma sonrasi")
    readHomeScreen(afterFirst).forEach { it.show() }
    println("tek seferlik: sunucu degisti, is bir daha calismadi")
    readHomeScreen(afterFirst).forEach { it.show() }
    val afterSecond = runWork(required, required, afterFirst, second, keys)
    println("donemsel: ikinci calisma sonrasi")
    readHomeScreen(afterSecond).forEach { it.show() }
}
```

```text
tek seferlik: ilk calisma sonrasi
fiyat: anahtar=urun.fiyat | deger=125 -> disk
stok: anahtar=urun.stok | deger=8 -> disk
kampanya: anahtar=kampanya.kod | deger=yok -> varsayilan
tek seferlik: sunucu degisti, is bir daha calismadi
fiyat: anahtar=urun.fiyat | deger=125 -> disk
stok: anahtar=urun.stok | deger=8 -> disk
kampanya: anahtar=kampanya.kod | deger=yok -> varsayilan
donemsel: ikinci calisma sonrasi
fiyat: anahtar=urun.fiyat | deger=130 -> disk
stok: anahtar=urun.stok | deger=6 -> disk
kampanya: anahtar=kampanya.kod | deger=yok -> varsayilan
```

Tek seferlik iş fiyatı 125 yaptı ve sunucu 130 söylese de ekran 125 gösterdi: iş bir daha çalışmadığı için disk değişmedi. Dönemsel iş ikinci çalışmada diski 130 ve 6 yaptı. Üç aşamada da kök aynı: disk. Değişen, diskin değeridir. Kural değerin güncel olup olmadığını söylemez; sunucu değerini yan yana koyduğumuz için eskiyi görürüz.

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

Kısıt sağlanmazsa ne olur? İki durum deneyelim. Birincide disk boş ve şarj yok. İkincisinde disk önceki bir çalışmadan kalma değerleri taşıyor ve ağ yok. İkisinde de iş gereken kısıtları bulamıyor.

```kotlin
// Main.kt — kisit saglanmadikca is calismaz, okuma varsayilan ya da eski disk kalir
fun main() {
    val required = setOf("ag-bagli", "sarjda")
    val network = Tier("ag", mapOf("urun.fiyat" to "125", "urun.stok" to "8", "kampanya.kod" to "YAZ10"))
    val keys = listOf("urun.fiyat", "urun.stok", "kampanya.kod")
    val old = mapOf("urun.fiyat" to "120", "urun.stok" to "9")
    val states = listOf(
        Triple("bos disk, sarj yok", emptyMap<String, String>(), setOf("ag-bagli")),
        Triple("eski disk, ag yok", old, setOf("sarjda")),
    )
    for ((name, disk, satisfied) in states) {
        println(name)
        val reads = readHomeScreen(runWork(required, satisfied, disk, network, keys))
        reads.forEach { it.show() }
        countOrigins(reads)
    }
}
```

```text
bos disk, sarj yok
fiyat: anahtar=urun.fiyat | deger=bilinmiyor -> varsayilan
stok: anahtar=urun.stok | deger=0 -> varsayilan
kampanya: anahtar=kampanya.kod | deger=yok -> varsayilan
bellek: 0
disk: 0
ag: 0
varsayilan: 3
eski disk, ag yok
fiyat: anahtar=urun.fiyat | deger=120 -> disk
stok: anahtar=urun.stok | deger=9 -> disk
kampanya: anahtar=kampanya.kod | deger=yok -> varsayilan
bellek: 0
disk: 2
ag: 0
varsayilan: 1
```

Boş diskte iş koşmadığı için üç okumanın üçü varsayılan kaldı. Eski diskte iki okuma eski değerle diskten geldi, kampanya varsayılan kaldı. Sunucu yeni değerleri biliyordu, ama iş onları diske taşımadı. Kural bunu görmez: sırada yalnız disk vardır ve yanıtı disk ya da yedek değer verir.

Ölçümün söylemediği şey, kısıtların ne kadar sürede sağlanacağı ve ekranın o zamana kadar ne göstermesi gerektiğidir. Birincisi platformun, ikincisi tasarımın kararıdır.

**VK4.** Model, bir kısıtı sağlanmış ya da sağlanmamış olarak alır. Platformda kısıtın kısmen sağlanması, sağlanıp yeniden bozulması ve işin kısıt sağlanana kadar bekleme biçimi modelde yoktur.

## Kapanış Tablosu

Kursun on dört dersi aynı soruyu sordu. Her dersin ölçtüğü okuma, dersin kökeni ve sınırlayıcı ölçümü tabloda. Köken sütunu, her dersin `Özet` bölümünde yazılı olandır.

| Ders | Ölçülen okuma | Köken | Sınırlayıcı ölçüm |
|---|---|---|---|
| Katman Modeli | Alan katmanından geçen fiyat | ağ | Bellekteki eski değer, ağ yenisini söylese de yanıt verir |
| Görünüm Modeli | Döndürmede adet ve fiyat | bellek | Süreç sonlanmasında okumalar ağa ve varsayılana düşer |
| Durum Tutucular | Kaydedilen arama metni ve sekme | disk | Kaydedilmeyen alan varsayılana ya da ağa düşer |
| Gözlemlenebilir Durum | Yükleme bitmeden okunan fiyat | varsayılan | Yükleme bitince fiyat ve stok bellekten gelir |
| Tek Yönlü Veri Akışı | Olayın kurduğu adet | bellek | Olay gelmeden dört okuma varsayılan |
| Bağımlılık Enjeksiyonu | Konteynerin kurduğu zincirde başlık | ağ | Sahte veri bellek basamağından yanıt verir |
| Depo Kalıbı | Depoya ilk giren okuma | bellek | Zincir sırası değişince köken ağa geçer |
| Yerel Veritabanı | Göçten geçen satır | disk | Yazılmamış alan varsayılan, doldurulunca disk |
| Anahtar–Değer Saklama | Hiç yazılmamış tercih | varsayılan | Yazılan tercih ve boş dizgi diskten gelir |
| Dosya ve Medya Depolama | Uygulamanın dizinindeki dosya | disk | Medya deposundaki dosya, kopyalanana kadar yanıtsız |
| Ağ İstemcisi | Çözülen yanıtın alanları | ağ | Çözülemeyen alan varsayılana düşer |
| Önbellekleme ve Çevrimdışı Destek | Yenileme sonrası okuma | disk | Ağ düşünce disk kalır, değer eskir |
| Sayfalı Veri Yükleme | Yüklenmemiş sayfanın ögesi | varsayılan | Yüklenen sayfada öge ağdan ya da diskten gelir |
| Arka Plan İşleri | Kısıt sağlanınca diske yazan işten sonraki okuma | disk | Kısıt sağlanmazsa varsayılan ya da eski disk |

Tablodaki kökenleri sayan blok, yazılmış bir listeyi sayar; kural ölçümü değildir. Aynı bloğa çekirdeğin sekiz okumasının dağılımını da koyuyoruz.

```kotlin
// Main.kt — on dort dersin ve cekirdegin kokenlerini sayar
fun main() {
    val lessons = listOf(
        "katman-modeli" to "ag", "gorunum-modeli" to "bellek", "durum-tutucular" to "disk",
        "gozlemlenebilir-durum" to "varsayilan", "tek-yonlu-veri-akisi" to "bellek",
        "bagimlilik-enjeksiyonu" to "ag", "depo-kalibi" to "bellek", "yerel-veritabani" to "disk",
        "anahtar-deger-saklama" to "varsayilan", "dosya-ve-medya-depolama" to "disk",
        "ag-istemcisi" to "ag", "onbellekleme" to "disk", "sayfali-veri-yukleme" to "varsayilan",
        "arka-plan-isleri" to "disk",
    )
    val core = mapOf("bellek" to 2, "disk" to 3, "ag" to 1, "varsayilan" to 2)
    println("dersler: ${lessons.size}")
    for (name in listOf("bellek", "disk", "ag", "varsayilan")) {
        println("$name: ${lessons.count { it.second == name }}")
    }
    println("cekirdek okumalar: ${core.values.sum()}")
    for ((name, n) in core) {
        println("$name: $n")
    }
}
```

```text
dersler: 14
bellek: 3
disk: 5
ag: 3
varsayilan: 3
cekirdek okumalar: 8
bellek: 2
disk: 3
ag: 1
varsayilan: 2
```

On dört dersin üçü bellek, beşi disk, üçü ağ, üçü varsayılan. Çekirdeğin sekiz okumasının dağılımı ise 2, 3, 1, 2'dir. İkisi aynı şey değildir: çekirdek sekiz okumayı, tablo on dört dersi sayar. Sayıların benzer görünmesi bir kural değildir; birinin diğerini öngörmesi beklenmez.

## Özet

- Bu dersin kökeni: disk. Kısıt sağlanınca iş ağdan çekip diske yazar ve ekranın sonraki okuması diskten gelir.
- İşin ekrandan farkı, yenilemeyi ekran açılmadan önce yapmasıdır; ağ okumanın zincirine girmez.
- Tek seferlik iş bir kez, dönemsel iş her dönemde diski yeniler; iş çalışmadıkça disk eski kalır.
- Kısıt sağlanmadıkça iş çalışmaz: okuma boş diskte varsayılan, eski diskte eski değerle disk olur.
- Kapanış tablosu on dört dersin kökenini yan yana koyar: bellek 3, disk 5, ağ 3, varsayılan 3.

## Kurs Kapanışı

Bu kurs, Android uygulamasında bir okumanın yanıtının hangi basamaktan geldiğini on dört derste ölçtü: mimari katmanlardan görünüm modeline, durum tutuculardan bağımlılık enjeksiyonuna, depodan yerel veritabanına, tercih ve dosya depolamadan ağ istemcisine, önbellekten sayfalı yüklemeye ve arka plan işlerine. Ölçü hep aynıydı ve kural hep yalnız sırayı gördü; tazelik, doğruluk ve tasarım kararları ölçünün dışında kaldı. Sıradaki kurs, `Platform Servisleri ve Tümleştirmeler`, uygulamanın platform servisleriyle ve dış tümleştirmelerle kurduğu ilişkiyi konu alır.
