Mobil geliştirmede Main Thread — nedir, rolü ve çalışma prensibi

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

Main Thread — mobil uygulamalardaki ana yürütme iş parçacığıdır ve tüm kullanıcı arayüzünü işler: dokunmalar, işleme, düzen güncellemeleri ve animasyonlar. iOS'ta bu RunLoop.main, Android'de — Looper.getMainLooper()'dır. Bu iş parçacığındaki herhangi bir uzun süreli işlem UI'yı bloke eder ve ANR'ye (Android) veya arayüz donmasına (iOS) neden olur. Apple UIKit Belgeleri'ne göre, UI sınıfları iş parçacığı güvenli değildir ve yalnızca Main Thread'den çağrı gerektirir.

Önemli Noktalar

  • Main Thread — iOS ve Android'de UI'yı güncelleyebilen tek iş parçacığı
  • Main Thread'i 5 saniyeden fazla bloke etmek ANR'ye (Android) veya arayüz donmasına (iOS) neden olur
  • DispatchQueue.main (iOS) ve runOnUiThread / Handler(Looper.getMainLooper()) (Android) — ana iş parçacığına dönme yolları
  • iOS ve Android UI çerçeveleri iş parçacığı güvenli değildir: UIKit, AppKit, Android View System
  • Main Thread Checker — arka plan iş parçacıklarından UI çağrılarını tespit etmek için Xcode'da yerleşik araç

Main Thread Nedir

Main Thread, uygulama başlatıldığında işletim sistemi tarafından oluşturulan ve tüm kullanıcı arayüzü olaylarını işlemekten sorumlu olan iş parçacığıdır. Mobil platformlar bağlamında, Main Thread aynı zamanda UI Thread olarak da adlandırılır, çünkü işleme, dokunma işleme ve animasyonlarla ilgili tüm işlemler burada yürütülür. Her uygulamanın tam olarak bir Main Thread'i vardır ve tüm UI çerçeveleri (UIKit, AppKit, Android Views, Compose UI) iş parçacığı güvenli değildir — diğer iş parçacıklarından çağrıldıklarında doğru çalışmayı garanti etmezler.

Mimari olarak, Main Thread Event Loop desenini uygular: iş parçacığı yeni olayları (dokunmalar, sistem bildirimleri, zamanlayıcılar) sonsuza kadar bekler ve bunları sıra düzeninde işler. Bir olay işlenirken, sonraki sırada bekler. İşleme 100-200 milisaniyeden uzun sürerse, kullanıcı bir gecikme (jank) fark eder. 5 saniyeden (Android) uzun sürerse — sistem bir ANR (Application Not Responding) diyaloğu gösterir ve uygulamayı kapatmayı önerir.

Main Thread'i anlamanın önemi abartılamaz: mobil uygulamalardaki performans sorunlarının %90'ının kaynağıdır. Geliştiriciler genellikle ağır işlemleri (ağ, dosyalar, JSON ayrıştırma, resim sıkıştırma) arka plan iş parçacıklarına taşımayı unuturlar. Bir öykünücüde 10 milisaniye süren bir işlem, yavaş diskli gerçek bir cihazda 500 milisaniye sürebilir ve gözle görülür gecikmeye neden olabilir.

UI Neden Yalnızca Main Thread'de Güncellenmelidir

İş parçacığı güvenli olmayan UI çerçeveleri, UIKit (2007) ve Android'in (2008) ilk sürümlerinde alınan mimari bir karardır. Ana neden performanstır: kilitler (locks) aracılığıyla UI bileşenlerine erişimi senkronize etmek, her işleme işlemine ek yük getirir. Bunun yerine, çerçeveler tüm UI değişikliklerinin kesinlikle tek bir iş parçacığında gerçekleştirilmesini gerektirir ve ek yük olmadan yarış koşullarını (race conditions) ortadan kaldırır.

İki arka plan iş parçacığının aynı anda textView.setText() çağırdığını hayal edin. UI iş parçacığı güvenli olsaydı, her iki çağrı da bir mutex aracılığıyla senkronize olur ve işlemeyi %20-40 yavaşlatırdı. Mevcut mimaride, bir arka plan iş parçacığından yapılan herhangi bir UI çağrısı ya yok sayılır ya da çökmeye neden olur (iOS'ta — Main Thread Checker Exception, Android'de — CalledFromWrongThreadException). İstisna, Android'de işlemenin ayrı bir iş parçacığından gerçekleştirilebildiği SurfaceView ve TextureView'dır.

Modern mobil çerçeveler (SwiftUI, Jetpack Compose) bu sınırlamayı sürdürür: SwiftUI, State ve ObservedObject'teki tüm değişikliklerin Main Thread'de gerçekleşmesini gerektirir, ancak işlemenin kendisi kısmen arka plan iş parçacıklarına aktarılır. Jetpack Compose da Main Thread'de State değişikliği bekler. İstisna, açıkça belgelendiğinde diğer iş parçacıklarından çağrılabilen drawBehind ve layout ile ilgili Compose değiştiricileridir.

iOS'ta Main Thread: RunLoop.main ve DispatchQueue.main

DispatchQueue.main — iOS'ta Main Thread'e kod göndermek için birincil mekanizmadır. Uygulamanın ana RunLoop'una bağlı seri bir kuyruktur. Kendisine gönderilen tüm bloklar, varış sırasına göre sırayla yürütülür. Main Thread'den State'i değiştirirseniz veya setNeedsLayout()'u çağırırsanız SwiftUI ve UIKit otomatik olarak güncellenir. Bir arka plan görevinden sonuçların eşzamansız olarak döndürülmesi için DispatchQueue.main.async {} kullanın.

Objective-C-Swift köprüsünde, Thread.isMainThread da mevcuttur — geçerli kodun ana iş parçacığında yürütülüp yürütülmediğini kontrol eden bir özelliktir. Mevcut UIKit projeleri için bu standart bir desendir: if Thread.isMainThread { updateUI() } else { DispatchQueue.main.async { updateUI() } }. SwiftUI'de bu kontrol genellikle gerekli değildir, çünkü çerçeve body ve modifier'ın Main Thread'de yürütülmesini garanti eder.

swift
import UIKit

class ViewController: UIViewController {

    let imageView = UIImageView()

    func loadImageFromNetwork() {
        // Arka plan iş parçacığı: resim indiriliyor
        DispatchQueue.global(qos: .background).async { [weak self] in
            guard let url = URL(string: "https://example.com/image.png"),
                  let data = try? Data(contentsOf: url),
                  let image = UIImage(data: data)
            else { return }

            // UI'yı güncellemek için Main Thread'e dön
            DispatchQueue.main.async {
                self?.imageView.image = image
                self?.imageView.setNeedsLayout()
            }
        }
    }

    // Kodun Main Thread'de yürütülüp yürütülmediğini kontrol et
    func safeUpdateUI() {
        if Thread.isMainThread {
            updateUI()
        } else {
            DispatchQueue.main.async {
                self.updateUI()
            }
        }
    }

    private func updateUI() {
        print("Main Thread'de UI güncellendi")
    }
}

Örnekte, loadImageFromNetwork() doğru deseni gösterir: URLSession veya Data(contentsOf:) DispatchQueue.global aracılığıyla bir arka plan iş parçacığında yürütülür, ardından sonuç UIImageView'i güncellemek için DispatchQueue.main'e döndürülür. DispatchQueue.main.async olmadan, uygulama bir arka plan iş parçacığından UIKit'i çağırırken NSInternalInconsistencyException ile çökecektir.

DispatchQueue.main.async — Garantili Dönüş

iOS'ta Main Thread'de kod yürütmenin en güvenilir yolu, DispatchQueue.main.async aracılığıyla açık göndermedir. Zaten Main Thread'de olsanız bile, async gönderme soruna neden olmaz: GCD bunu bir sonraki RunLoop yinelemesinde işler. Senkron yürütme için DispatchQueue.main.sync kullanın, ancak bu Main Thread'den çağrılırsa kilitlenmeye neden olabilir. Kural: sonuçları döndürmek için async, yalnızca ana iş parçacığında olmadığınızdan eminseniz sync.

Main Thread'in Temeli Olarak RunLoop.main

RunLoop.main, iOS'un ana olay kuyruğuyla ilişkili bir CFRunLoop nesnesidir. Giriş kaynaklarını (dokunma olayları), zamanlayıcıları ve DispatchQueue.main bloklarını işler. Her işleme karesi (60/120 FPS), dikey senkronizasyon darbesinden (VSync) önce RunLoop'daki tüm işlemlerin tamamlanmasını gerektirir. Main Thread'deki işlemler 16,6 ms'den (60 FPS) veya 8,3 ms'den (120 FPS) uzun sürerse, uygulama kareleri düşürür ve görsel olarak jank veya stutter olarak ortaya çıkar.

Android'de Main Thread: Looper ve Handler

Looper.getMainLooper() — Android'de ana iş parçacığıyla çalışmak için ana mekanizmadır. Android'deki her Main Thread, kuyruktan (MessageQueue) sonsuza kadar mesaj çıkaran ve bunları işlenmek üzere bir Handler'a ileten bir Looper'a sahiptir. Activity.runOnUiThread() ve View.post(), Handler(Looper.getMainLooper()) etrafındaki üst düzey sarmalayıcılardır. Dispatchers.Main ile Kotlin Coroutines, ana iş parçacığına dönmenin modern yoludur.

Android ayrıca StrictMode sağlar — Main Thread'i bloke eden işlemleri tespit etmek için bir araç. StrictMode.setThreadPolicy() bir politika belirlemenize olanak tanır: ana iş parçacığında ağ çağrılarının (NetworkPolicy), disk okumalarının (DiskRead), disk yazmalarının (DiskWrite) yasaklanması. Bir politika ihlal edildiğinde, bir istisna oluşturulur veya logcat'e bir mesaj yazılır.

kotlin
// Android: Main Thread ve Kotlin Coroutines ile Çalışma
import android.os.Bundle
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.URL

class MainActivity : ComponentActivity() {

    private lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        textView = TextView(this)
        setContentView(textView)

        // Örnek: Eşzamansız Veri Yükleme
        lifecycleScope.launch {
            val result = loadData() // Dispatchers.IO'da yürütülüyor
            textView.text = result // Main Thread'de UI
        }
    }

    private suspend fun loadData(): String {
        return withContext(Dispatchers.IO) {
            URL("https://api.example.com/data").readText()
        }
    }
}

// Main Thread İhlallerini Tespit Etmek İçin StrictMode
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        StrictMode.setThreadPolicy(
            StrictMode.ThreadPolicy.Builder()
                .detectDiskReads()
                .detectDiskWrites()
                .detectNetwork()
                .penaltyLog()
                .build()
        )
    }
}

Kotlin örneği, lifecycleScope.launch aracılığıyla Dispatchers.Main'in ve withContext aracılığıyla Dispatchers.IO'nun doğru kullanımını gösterir. Tüm ağ çalışması IO dağıtıcısında gerçekleştirilirken, TextView güncellemesi, lifecycleScope'teki launch varsayılan olarak Dispatchers.Main kullandığı için otomatik olarak Main Thread'de gerçekleşir. Application.onCreate() içindeki StrictMode, ana iş parçacığındaki yanlışlıkla ağ çağrılarını ve disk işlemlerini durdurur.

Main Thread İhlallerini Tespit Etme

Main Thread Checker — Xcode'da yerleşik bir araçtır (Xcode 9'dan beri mevcuttur) ve arka plan iş parçacıklarından UIKit, AppKit ve diğer UI çerçevelerine yapılan çağrıları tespit eder. Hata ayıklama sırasında, Main Thread Checker tüm UI-API çağrılarını analiz eder ve bir ihlal tespit ettiğinde ayrıntılı bir yığın iziyle birlikte bir kesme noktası gösterir. Gerçek cihazlarda (sürüm yapılarında), Main Thread Checker çalışmaz — ihlaller çökme veya yanlış davranış olarak ortaya çıkar.

Android'de eşdeğeri StrictMode'dur (yukarıda açıklanmıştır) ve yerleşik günlük dedektörüdür: bir arka plan iş parçacığından View.setText() veya View.invalidate() çağrıldığında, Android CalledFromWrongThreadException fırlatır. Ek olarak, Android Studio Profiler Main Thread'de hangi işlemlerin yürütüldüğünü gösterir. Main Thread'de ağ veya dosya işlemleri görüyorsanız — bu bir sorunun açık işaretidir.

AraçPlatformNe Tespit Eder
Main Thread CheckeriOS (Xcode)Arka plan iş parçacıklarından UIKit/AppKit çağrıları
StrictModeAndroidMain Thread'de ağ, disk, uzun işlemler
Android Studio ProfilerAndroidZaman içinde Main Thread yükünün görselleştirilmesi
Time ProfileriOS (Instruments)Main Thread'de yöntem yürütme süresinin ölçümü
HUD / DispatchQueue.main.asynciOSHata ayıklama yoluyla UI bloke etmenin görsel göstergesi

Görsel Desen: Sarsıntılı Kaydırma

Main Thread bloke etmenin en belirgin belirtisi sarsıntılı kaydırmadır (janky scroll). Bir kullanıcı UITableView veya RecyclerView'ı kaydırdığında, sistem bir sonraki karenin 16 ms içinde hazır olmasını bekler. Main Thread'de resim kod çözme veya JSON ayrıştırma yapılıyorsa, kare işleme gecikir ve kullanıcı takılmalar görür. Teşhis için bir profil oluşturucu kullanın: prepareDisplay() veya layoutSubviews() >16 ms sürüyorsa — veriler yanlış iş parçacığında işleniyor demektir.

Main Thread Bloke Etmenin Tipik Senaryoları

İlk senaryo — Main Thread'de URLConnection veya Data(contentsOf:) aracılığıyla senkron ağ isteği. Android'de, detectNetwork() ile StrictMode bu ihlali hemen yakalar. iOS'ta, senkron bir URLSession açık bir hata vermez, ancak istek sırasında (1-10 saniye) UI donar. Çözüm: eşzamansız geri aramalı URLSession.dataTask (iOS) veya Retrofit/OkHttp (Android) kullanın.

İkinci senaryo — resim kod çözme ve sıkıştırma. Android'de ana iş parçacığında UIImage(data:) veya BitmapFactory.decodeResource() jank'ın en yaygın nedenlerinden biridir. 4000x3000 piksel bir resim 50-150 milisaniyede çözülür ve 16 ms sınırını aşar. Çözüm: arka plan iş parçacığında kod çözmeyi garanti eden ImageLoader (Kingfisher, Coil, Glide) kullanın.

Üçüncü senaryo — JSON ayrıştırma. Main Thread'de JSONSerialization (iOS) veya JSONObject (Android) aracılığıyla API yanıtını ayrıştırma. Küçük bir 100 KB JSON bile 5-15 milisaniyede ayrıştırılır, ancak yavaş cihazlarda — 50 milisaniyeye kadar. Diğer işlemlerle birleştiğinde bu birikir ve kare düşüşlerine yol açar. Çözüm: parse()'ı arka plan iş parçacığında çağrılan kotlinx.serialization/Decodable kullanın ve Main Thread'de yalnızca sonuç atamasını bırakın.

Sıkça Sorulan Sorular

Mobil geliştirmede Main Thread nedir?

Main Thread, tüm UI işlemlerinin (dokunma işleme, ekran işleme, animasyonlar, düzen güncellemeleri) gerçekleştirildiği uygulamanın ana iş parçacığıdır. iOS'ta bu RunLoop.main ve DispatchQueue.main, Android'de — Looper.getMainLooper()'dır. Tüm UI çerçeveleri (UIKit, Android Views) iş parçacığı güvenli değildir ve yalnızca Main Thread'den çağrı gerektirir. Bu iş parçacığındaki herhangi bir uzun süreli işlem arayüzü bloke eder.

UI neden yalnızca ana iş parçacığında güncellenmelidir?

UI çerçeveleri performans için mimari olarak iş parçacığı güvenli değildir: kilitler aracılığıyla erişimi senkronize etmek, her işleme işlemine %20-40 ek yük ekler. UIKit ve Android geliştiricileri, mutex olmadan yarış koşullarının ortadan kaldırıldığı tek iş parçacıklı bir model seçti. Tüm UI değişiklikleri kesinlikle Main Thread'de gerçekleştirilmelidir — aksi takdirde çökme veya yanlış görüntüleme.

Bir arka plan iş parçacığından Main Thread'e sonuç nasıl döndürülür?

iOS'ta ana kuyruğa kod göndermek için DispatchQueue.main.async { } kullanın. Android'de — runOnUiThread { } veya Dispatchers.Main ile Kotlin Coroutines. Modern yaklaşım coroutine'lerdir: arka plan çalışması için withContext(Dispatchers.IO) ve launch'te otomatik Dispatchers.Main. Java projeleri için Handler(Looper.getMainLooper()).post { }.

ANR nedir ve Main Thread ile nasıl ilişkilidir?

ANR (Application Not Responding), Main Thread 5 saniyeden fazla bloke edilirse görünen bir Android diyaloğudur. ANR, sistemin uygulamadan bir giriş olayına (dokunma, tuşa basma) yanıt almadığı veya bir BroadcastReceiver'ın 10 saniye içinde tamamlanmadığı anlamına gelir. Neden, Main Thread'deki senkron bir işlemdir: ağ isteği, veritabanı çalışması, karmaşık hesaplamalar. iOS'ta eşdeğer, diyalogsuz UI donmasıdır.

SwiftUI Main Thread'de yürütmeyi kontrol eder mi?

SwiftUI otomatik olarak body ve modifier'ın Main Thread'de yürütülmesini garanti eder. Ancak, bir arka plan iş parçacığından (örneğin, bir URLSession temsilcisinden) @Published özelliklerinde veya State'te yapılan değişiklikler sorunlara neden olabilir. ObservableObject sınıfları için @MainActor kullanın, böylece tüm yöntemleri Main Thread'de yürütülür. SwiftUI 5.5+'ta @MainActor, ObservableObject için otomatik olarak eklenir.

Özet

  • Main Thread — UI için tek iş parçacığı: dokunmalar, işleme, düzen, animasyonlar; tüm UI çerçeveleri iş parçacığı güvenli değildir
  • Main Thread'i >5 saniye bloke etmek Android'de ANR'ye, iOS'ta — yerleşik diyalog olmadan arayüz donmasına neden olur
  • DispatchQueue.main (iOS) ve Dispatchers.Main / runOnUiThread (Android) — ana iş parçacığına dönme mekanizmaları
  • Ağ, JSON ayrıştırma, resim kod çözme — en sık yanlışlıkla Main Thread'de yürütülen işlemler
  • Main Thread Checker (Xcode) ve StrictMode (Android) hata ayıklama sırasında arka plan iş parçacıklarından UI çağrılarını tespit eder
  • SwiftUI Main Thread'de yürütmeyi garanti etmek için @MainActor kullanır, Jetpack Compose varsayılan olarak Dispatchers.Main kullanır
  • Profil oluşturucular (Instruments Time Profiler, Android Studio Profiler) Main Thread yükünü gösterir ve darboğazları bulmaya yardımcı olur

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