Mobil geliştirmede Background Thread: nedir, görevleri ve kullanım yöntemleri

Yazar: IT Sectr Yayınlanma: 2026-03-15 Okuma süresi: 11 dk

Background Thread — kullanıcı arayüzüyle ilişkili olmayan, uzun süreli işlemler (ağ istekleri, dosya işlemleri, JSON ayrıştırma, görüntü sıkıştırma, şifreleme ve veritabanı sorguları) için tasarlanmış bir yürütme iş parçacığıdır. iOS'ta arka plan iş parçacıkları GCD (DispatchQueue.global) ve OperationQueue aracılığıyla yönetilir; Android'de ise Executors, WorkManager ve Kotlin Coroutines (Dispatchers.IO, Dispatchers.Default) aracılığıyla yönetilir. Apple DispatchQueue Dokümantasyonu'na göre, arka plan işlemi tamamlandıktan sonra arayüzü güncellemek için sonucun Main Thread'e döndürülmesi gerekir.

Anahtar Noktalar

  • Background Thread UI'yı bloke eden işlemleri gerçekleştirir: ağ, dosyalar, JSON, hesaplamalar
  • iOS: Arka plan görevleri için DispatchQueue.global(qos:) ve OperationQueue
  • Android: Dispatchers.IO (ağ/dosyalar), Dispatchers.Default (hesaplamalar), WorkManager (arka plan görevleri)
  • Coroutines — arka plan çalışmasının modern standardı: withContext(Dispatchers.IO) callback hell olmadan iş parçacığı değiştirir
  • Sonuç Background Thread'ten UI güncellemesi için her zaman Main Thread'e döndürülür

Background Thread Nedir

Background Thread — uygulamada Main Thread olmayan ve UI'ya erişimi olmayan herhangi bir iş parçacığıdır. Görevi, arayüzün duyarlı kalması için ana iş parçacığını ağır işlemlerden kurtarmaktır. İşletim sistemi, arka plan iş parçacıklarını CPU çekirdeklerine dağıtarak birden çok görevin paralel olarak yürütülmesine olanak tanır. iOS, iş parçacığı havuzunu GCD aracılığıyla, Android ise Java Executors havuzları aracılığıyla otomatik olarak yönetir.

Olayları sırayla (birbiri ardına) işleyen Main Thread'un aksine, arka plan iş parçacıkları yalnızca CPU çekirdeği sayısıyla sınırlı olarak paralel olarak çalışabilir. Örneğin, 8 çekirdekli bir cihazda önemli bir yavaşlama olmadan 8'e kadar paralel arka plan görevi çalıştırılabilir. Ancak aşırı sayıda iş parçacığı (yüzlerce), thread starvation — çekirdekler için rekabet ve bağlam değiştirme (context switch) yükünün artmasına yol açar.

Quality of Service (QoS) — bir arka plan görevinin önceliğini belirtmeye olanak tanıyan iOS mekanizmasıdır. Değerler: .userInteractive (en yüksek, neredeyse Main Thread), .userInitiated (kullanıcı sonucu bekliyor), .default (standart), .utility (kullanıcı doğrudan beklemiyor), .background (en düşük, senkronizasyon ve indeksleme için). Android'de eşdeğeri, 1'den 10'a kadar Thread.setPriority()'dir, ancak Android ayrıca iş parçacığı önceliklerinin grup yönetimi için cgroups kullanır.

iOS'ta Background Thread: GCD ve DispatchQueue.global

DispatchQueue.global(qos:) — iOS'ta bir arka plan kuyruğu elde etmenin birincil yoludur. GCD (Grand Central Dispatch) otomatik olarak bir iş parçacığı havuzu oluşturur ve görevleri çekirdeklere dağıtır. DispatchQueue.global(qos: .background).async {} çağrısı, en düşük öncelikli arka plan kuyruğuna bir blok gönderir. Sonucu hemen gereken görevler için .userInitiated veya .utility kullanın.

OperationQueue — GCD üzerinde işlemler arasında bağımlılıklar, maksimum eşzamanlı işlem sayısı (maxConcurrentOperationCount) ve öncelikler ayarlamaya olanak tanıyan daha yüksek seviyeli bir soyutlamadır. OperationQueue, karmaşık çoklu görev zincirleri (dosya indir → çıkart → önbelleğe kaydet) için kullanışlıdır. Varsayılan olarak, aksi belirtilmediği sürece OperationQueue arka plan iş parçacıklarını kullanır.

swift
import UIKit

class ImageDownloader {

    func downloadImagesSequentially() {
        let urls = ["https://example.com/1.png", "https://example.com/2.png"]

        // maxConcurrentOperationCount = 2 ile OperationQueue
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 2
        queue.qualityOfService = .utility

        for urlString in urls {
            queue.addOperation {
                guard let url = URL(string: urlString),
                      let data = try? Data(contentsOf: url)
                else { return }

                DispatchQueue.main.async {
                    print("Yüklendi: \(url.lastPathComponent)")
                }
            }
        }
    }

    // GCD: farklı QoS ile küresel arka plan kuyruğu
    func backgroundTaskWithQoS() {
        DispatchQueue.global(qos: .userInitiated).async {
            // Yüksek öncelik — kullanıcı sonucu bekliyor
            let result = self.heavyComputation()
            DispatchQueue.main.async {
                self.showResult(result)
            }
        }
    }

    private func heavyComputation() -> String {
        Thread.sleep(forTimeInterval: 2) // iş simülasyonu
        return "Hesaplama sonucu"
    }

    private func showResult(_ result: String) {
        print("Result on Main: \(result)")
    }
}

Örnekte, OperationQueue qualityOfService = .utility aracılığıyla arka plan QoS ile iki görüntüyü paralel olarak yükler (maxConcurrentOperationCount = 2). GCD yöntemi backgroundTaskWithQoS, kullanıcının sonucunu beklediği bir görev için .userInitiated ile küresel bir kuyruk kullanır. Her iki yaklaşım da UI'yı güncellemek için DispatchQueue.main'e dönerek sonlanır — bu iOS'ta zorunlu bir gerekliliktir.

Serial ve Concurrent Arka Plan Kuyrukları

GCD iki tür kuyruğu destekler: seri (serial) ve eşzamanlı (concurrent). Seri kuyruklar görevleri birbiri ardına yürütür — bu, kilit olmadan paylaşılan bir kaynağa (dosya, DB) erişmek için kullanışlıdır. Eşzamanlı kuyruklar görevleri paralel olarak yürütür ve bunları mevcut çekirdeklere dağıtır. DispatchQueue.global her zaman eşzamanlıdır. Seri bir kuyruk oluşturmak için DispatchQueue(label: "com.app.queue") kullanın.

Android'te Background Thread: Executors ve Dispatchers

Android, arka plan iş parçacıkları için birden çok soyutlama düzeyi sağlar. Klasik yaklaşım java.util.concurrent.Executors.newFixedThreadPool(n) veya Executors.newCachedThreadPool()'dur. Modern yaklaşım, Dispatchers.IO (G/Ç için: ağ, dosyalar, DB) ve Dispatchers.Default (CPU yoğun görevler için: sıralama, görüntü işleme) ile Kotlin Coroutines'dir. WorkManager, ertelenmiş ve garantili arka plan görevleri içindir.

HandlerThread — kendi Looper'ına (mesaj kuyruğu) sahip bir arka plan iş parçacığı oluşturmak için özel bir Android sınıfıdır. Executors'tan farklı olarak HandlerThread, bir Handler aracılığıyla mesaj ve Runnable göndermeye olanak tanır. Kuyruğa alınması gereken işlemler (örneğin, sıralı DB yazma) için kullanılır. Kullanımdan sonra, kaynakları serbest bırakmak için quit() veya quitSafely() çağrılmalıdır.

kotlin
// Android: Executors ve Coroutines Dağıtıcıları
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.concurrent.Executors

class DataRepository {

    private val ioExecutor = Executors.newFixedThreadPool(4)

    // Executors aracılığıyla klasik yaklaşım
    fun loadDataLegacy(callback: (String) -> Unit) {
        ioExecutor.execute {
            val result = readFromFile()
            val handler = android.os.Handler(android.os.Looper.getMainLooper())
            handler.post { callback(result) }
        }
    }

    // Coroutines aracılığıyla modern yaklaşım
    suspend fun loadDataCoroutines(): String {
        return withContext(Dispatchers.IO) {
            // Dosya işlemi — arka plan havuzunda yürütülüyor
            readFromFile()
        }
        // Sonuç otomatik olarak Dispatchers.Main'e döner
    }

    // Dispatchers.Default'ta CPU yoğun görev
    suspend fun processImage(pixels: IntArray): IntArray {
        return withContext(Dispatchers.Default) {
            // Sıralama, filtreleme — Default havuzunda yürütülüyor
            pixels.sortedArray()
        }
    }

    private fun readFromFile(): String {
        Thread.sleep(1000) // dosyadan okuma simülasyonu
        return "file_content"
    }

    fun cleanup() {
        ioExecutor.shutdown()
    }
}

DataRepository örneği, Android'te arka plan iş parçacıklarının evrimini gösterir. Eski yöntem loadDataLegacy, Main Thread'e dönmek için bir Handler ile Executors.newFixedThreadPool(4) kullanır. Modern loadDataCoroutines, withContext(Dispatchers.IO) kullanır — coroutine, iş parçacığını bloke etmeden yürütme sırasında askıya alınır ve otomatik olarak Main Thread'de devam eder. Dispatchers.Default, CPU'ya bağlı işlemler (sıralama, filtreleme, veri dönüştürme) için önerilir.

Arka Plan Görevlerinin Modern Standardı Olarak Coroutines

Kotlin Coroutines — yalnızca iş parçacıklarıyla çalışmanın bir yolu değil, temelde farklı bir modeldir: asenkron görevler belirli bir iş parçacığına bağlı değildir ve bloke etmeden askıya alınabilir. Bu, arka plandayken bir coroutine'in bir iş parçacığını işgal etmediği, diğer görevler için serbest bıraktığı anlamına gelir. Askıya alma mekanizması, thread starvation olmadan 4–8 iş parçacıklı bir havuzda yüz binlerce eşzamanlı görevin yürütülmesine olanak tanır.

Üç ana dağıtıcı: Dispatchers.Main (UI, bir iş parçacığı), Dispatchers.IO (varsayılan olarak bloke edici işlemler için 64 iş parçacığı: ağ, dosyalar, DB), Dispatchers.Default (CPU çekirdeği sayısına eşit, yoğun hesaplamalar için). Bunları withContext aracılığıyla birleştirerek geliştirici, callback oluşturmadan iş parçacıkları arasında geçiş yapar. withContext, görev tamamlanana kadar kontrolü geri vermeyen bir suspend işlevidir.

kotlin
// Coroutines: arka plan görevlerinin bileşimi
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay

suspend fun loadUserProfile(userId: String): UserProfile =
    coroutineScope {
        // Farklı kaynaklardan paralel veri yükleme
        val user = async(Dispatchers.IO) { fetchUser(userId) }
        val posts = async(Dispatchers.IO) { fetchPosts(userId) }
        val avatar = async(Dispatchers.Default) {
            processAvatar(fetchAvatar(userId))
        }

        // await() — tüm görevler tamamlanana kadar askıda kalır
        UserProfile(
            user = user.await(),
            posts = posts.await(),
            avatar = avatar.await()
        )
    }

data class UserProfile(
    val user: String,
    val posts: List<String>,
    val avatar: ByteArray
)

suspend fun fetchUser(id: String): String { delay(300); return "User:$id" }
suspend fun fetchPosts(id: String): List<String> { delay(500); return listOf("Post1") }
suspend fun fetchAvatar(id: String): ByteArray { delay(200); return ByteArray(1024) }
suspend fun processAvatar(data: ByteArray): ByteArray { delay(100); return data }

loadUserProfile işlevi, async aracılığıyla üç paralel arka plan görevi başlatır. fetchUser ve fetchPosts IO'ya bağlıdır (ağ), Dispatchers.IO'da yürütülür. processAvatar CPU'ya bağlıdır (görüntü işleme), Dispatchers.Default'da yürütülür. await(), tüm görevler tamamlanana kadar coroutine'i askıya alır. Toplam yürütme süresi, üç görevin toplamına değil, maksimum süresine (fetchPosts için 500 ms) eşittir. Bu, sıralı yürütmeye kıyasla coroutines'in önemli bir avantajıdır.

Yapılandırılmış Eşzamanlılık: Sızıntıları Önleme

Structured concurrency — her coroutine'in bir üst kapsama sahip olduğu ve üstün iptal edilmesinin alt coroutine'leri otomatik olarak iptal ettiği ilkedir. Android'de lifecycleScope, Activity yok edildiğinde tüm coroutine'leri iptal eder. viewModelScope, ViewModel temizlendiğinde bunu yapar. Bu, arka plan görev sızıntılarını önler: kullanıcı ekranı kapatırsa, arka plandayken coroutine artık ihtiyaç duyulmayan verileri yüklemeye devam etmez.

WorkManager: Android için Arka Plan Görevleri

WorkManager — cihaz yeniden başlatıldıktan veya uygulama kapatıldıktan sonra bile tamamlanması gereken arka plan görevlerini yürütmek için bir Android Jetpack kitaplığıdır. Uygulama süreci içinde yaşayan Executors ve coroutine'lerin aksine WorkManager, görevi uygun koşullar altında (ağ kullanılabilirliği, pil şarjı, boş alan) yürütmeyi garanti eden bir sistem dağıtıcısına teslim eder. WorkManager, veri senkronizasyonu, günlük yükleme ve yedekleme için uygundur.

WorkManager'daki bir görev, Worker'ı (veya coroutine'ler için CoroutineWorker) genişleten bir sınıftır. Worker.doWork(), WorkManager tarafından sağlanan bir arka plan iş parçacığında yürütülür. Sonuç, Result.success(), Result.retry() veya Result.failure() aracılığıyla döndürülür. Görevler zincirlenebilir: oneTimeWorkRequest.andThen(nextRequest).enqueue(). WorkManager, kısıtlamaları (Constraints) dikkate alarak en uygun yürütme zamanını kendisi seçer.

kotlin
// Coroutines ile WorkManager
import android.content.Context
import androidx.work.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class SyncWorker(
    appContext: Context,
    workerParams: WorkerParameters
) : CoroutineWorker(appContext, workerParams) {

    override suspend fun doWork(): Result {
        // Dispatchers.Default'ta yürütülüyor (varsayılan)
        return withContext(Dispatchers.IO) {
            try {
                syncDataToServer()
                Result.success()
            } catch (e: Exception) {
                if (runAttemptCount < 3) Result.retry() else Result.failure()
            }
        }
    }

    private suspend fun syncDataToServer() {
        // Senkronizasyon simülasyonu
        delay(1000)
    }
}

// Kısıtlamalarla WorkManager görevi başlatma
fun scheduleSync(context: Context) {
    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresBatteryNotLow(true)
        .build()

    val syncWork = OneTimeWorkRequestBuilder<SyncWorker>()
        .setConstraints(constraints)
        .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, java.util.concurrent.TimeUnit.SECONDS)
        .build()

    WorkManager.getInstance(context).enqueue(syncWork)
}

SyncWorker, coroutine'leri destekleyen Worker sürümü olan CoroutineWorker'ı genişletir. doWork(), Dispatchers.Default'da yürütülür ve withContext aracılığıyla ağ işlemleri için IO'ya geçer. Constraints, senkronizasyonun yalnızca ağ kullanılabilir olduğunda ve pil şarjı düşük seviyenin altında olmadığında başlamasını sağlar. EXPONENTIAL ile BackoffCriteria, yeniden deneme aralığını artırır: 10, 20, 40 saniye.

Düzenli Arka Plan Görevleri için PeriodicWorkRequest

Düzenli görevler (her 15 dakikada bir senkronizasyon, saatte bir analitik gönderme) için WorkManager, PeriodicWorkRequestBuilder sağlar. Minimum aralık 15 dakikadır. OneTimeWorkRequest'in aksine, PeriodicWorkRequest tam aralığa uyulmasını garanti etmez — sistem, pilden tasarruf etmek için birden çok periyodik görevi gruplayabilir. Tam aralıklar için AlarmManager kullanın, ancak Android 12+'nın tam alarmlar üzerindeki kısıtlamalarını göz önünde bulundurun.

Arka Plan İş Parçacıklarıyla Çalışırken Sık Yapılan Hatalar

İlk hata — her görev için yeni bir Thread oluşturmak. new Thread().start(), yığın için yaklaşık 1 MB ayıran yerel bir iş parçacığı oluşturur. 100 paralel görev için bu yalnızca yığınlar için 100 MB'dir, ayrıca bağlam değiştirme yükü de vardır. İş parçacığı havuzları kullanın: Executors.newFixedThreadPool(n) (Android) veya DispatchQueue.global() (iOS) — iş parçacıklarını yeniden kullanarak yükü katbekat azaltır.

İkinci hata — senkronizasyon olmadan birden çok arka plan iş parçacığından değişebilir duruma erişmek. İki arka plan iş parçacığı aynı anda aynı ArrayList veya HashMap'e yazarsa, yarış koşulları oluşur: Android'de ConcurrentModificationException, iOS'ta veri bozulması. Çözüm: iş parçacığı güvenli koleksiyonlar (ConcurrentHashMap, CopyOnWriteArrayList) kullanın veya tek bir kuyruk (DispatchQueue serial) aracılığıyla erişimi sıralayın.

Üçüncü hata — yaşam döngüsü yönetimi olmayan arka plan görevleri. Bir coroutine'i Activity veya ViewModel yaşam döngüsüne bağlamadan küresel kapsamda başlatmak sızıntılara yol açar: görev, ekran yok edildikten sonra da çalışmaya devam eder. Android'de lifecycleScope (Activity/Fragment) veya viewModelScope (ViewModel) kullanın. iOS'ta closure'larda weak self kullanın ve deinit'te görevleri iptal edin.

Sıkça Sorulan Sorular

Mobil uygulamalarda Background Thread nedir?

Background Thread — UI ile ilgili olmayan işlemlerin (ağ istekleri, dosya okuma/yazma, JSON ayrıştırma, hesaplamalar) yürütüldüğü bir iş parçacığıdır. Main Thread'i ağır işlerden kurtararak arayüzün duyarlı kalmasını sağlar. iOS'ta arka plan iş parçacıkları GCD (DispatchQueue.global) aracılığıyla; Android'de Executors veya Kotlin Coroutines (Dispatchers.IO, Dispatchers.Default) aracılığıyla yönetilir.

Dispatchers.IO ve Dispatchers.Default arasındaki fark nedir?

Dispatchers.IO bloke edici G/Ç işlemleri için tasarlanmıştır: dosya okuma, ağ istekleri, DB ile çalışma. 64 iş parçacıklı bir havuza sahiptir. Dispatchers.Default CPU yoğun görevler içindir: sıralama, filtreleme, görüntü işleme. Havuzu CPU çekirdeği sayısına eşittir. G/Ç işlemleri için Dispatchers.Default kullanmak tüm çekirdekleri bloke edebilir ve CPU görevleri için Dispatchers.IO kullanmak aşırı sayıda iş parçacığı oluşturabilir.

iOS'ta arka plan iş parçacığına nasıl geçilir?

DispatchQueue.global(qos: .background).async { } küresel arka plan kuyruğuna bir blok gönderir. Arka plan çalışması tamamlandıktan sonra, UI'yı güncellemek için DispatchQueue.main.async { } aracılığıyla ana iş parçacığına dönmek gerekir. Sıralı arka plan görevleri için maxConcurrentOperationCount = 1 ile OperationQueue veya DispatchQueue(label: "serial") kullanın.

Bir mobil uygulamada kaç tane arka plan iş parçacığı oluşturulabilir?

Önerilen arka plan iş parçacığı sayısı, IO'ya bağlı görevler için CPU çekirdeği sayısı artı 1'e eşittir. Modern 8 çekirdekli bir cihazda bu 9 iş parçacığıdır. Yüzlerce iş parçacığı oluşturmak thread starvation'a yol açar: işletim sistemi, görevleri yürütmekten daha fazla zamanını bağlam değiştirmeye harcar. iOS'ta GCD ve Android'de Executors, iş parçacığı havuzunu mevcut cihaz için otomatik olarak optimize eder.

Bir coroutine'den sonra Main Thread'e dönmek gerekli midir?

Kotlin Coroutines'te, coroutine bir Main kapsamında (lifecycleScope.launch, viewModelScope.launch) başlatıldıysa Main Thread'e dönüş otomatik olarak gerçekleşir. withContext(Dispatchers.IO) işlevi, coroutine'i bir IO iş parçacığında askıya alır ve tamamlandıktan sonra başlatıldığı dağıtıcıda (genellikle Main) otomatik olarak devam ettirir. DispatchQueue.main.async'in açık bir şekilde çağrılması gerekmez.

Özet

  • Background Thread — Main Thread'de çalıştırılmaması gereken işlemler için iş parçacığı: ağ, dosyalar, JSON ayrıştırma, hesaplamalar
  • iOS: DispatchQueue.global(qos:) ve OperationQueue, QoS desteği ile arka plan görevleri için ana API'lerdir
  • Android: Java için Executors, HandlerThread, WorkManager; Kotlin için Dispatchers.IO/Default + coroutines
  • Coroutines withContext ile callback olmadan ve bloke etmeden iş parçacığı değiştirir (askıya alma mekanizması)
  • WorkManager, kısıtlamaları dikkate alarak cihaz yeniden başlatıldıktan sonra bile arka plan görevlerinin yürütülmesini garanti eder
  • Hatalar: havuz yerine yeni Thread'ler oluşturmak, değişebilir duruma erişimde yarış koşulları, yaşam döngüsü bağlantısı eksikliğinden kaynaklanan sızıntılar
  • Sonuç arka plan iş parçacığından her zaman Main Thread'e döndürülür: Dispatchers.Main (Android) veya DispatchQueue.main.async (iOS) aracılığıyla

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun