Thread Nedir? UI Thread Neden Önemli?
Aynı Anda Birden Fazla Şey Yapmanın Bedeli
Bir uygulama açıyorsunuz. Üst kısımda animasyon dönüyor, arka planda sunucudan veri çekiliyor, liste güncelleniyor, aynı zamanda ses çalıyor. Tüm bunlar aynı anda gerçekleşiyor — ama nasıl?
İşte burada thread kavramı devreye giriyor.
Thread Nedir?
Thread, bir process içinde bağımsız olarak çalışabilen yürütme birimidir. Bir process'i bir fabrikaya benzetirseniz, thread'ler o fabrikadaki ayrı üretim bantlarıdır. Hepsi aynı fabrikayı paylaşır, aynı hammaddeye erişebilir, ama her biri kendi işini bağımsız olarak yürütür.
Bir Android uygulaması başlatıldığında otomatik olarak bir ana thread oluşturulur. İhtiyaç duyulduğunda bu ana thread'e ek olarak yeni thread'ler yaratılabilir. Tüm thread'ler aynı process belleğini paylaşır, yani aynı nesnelere ve değişkenlere erişebilirler.
Bu paylaşım güçlü ama aynı zamanda tehlikelidir. Birden fazla thread aynı veriye aynı anda erişmeye çalışırsa race condition adı verilen ve tahmin edilmesi son derece güç hatalara kapı aralanır.
Ana Thread: UI Thread
Android uygulamalarında ana thread aynı zamanda UI thread olarak da bilinir. Bu isim, UI thread'in üstlendiği birincil sorumluluğu açıkça ortaya koyar: tüm kullanıcı arayüzü işlemlerini yönetmek.
Ekrandaki her View'ın çizilmesi, her kullanıcı etkileşiminin işlenmesi, her animasyonun güncellenmesi bu tek thread üzerinde gerçekleşir. Android bu konuda son derece katıdır — başka bir thread'den bir View'ı güncellemeye çalışırsanız sistem bunu izin vermez ve CalledFromWrongThreadException fırlatır.
Bu kısıtlamanın sebebi var. Çoklu thread'lerin aynı View hiyerarşisine eş zamanlı erişmesi, son derece karmaşık senkronizasyon sorunlarına ve tutarsız görsel durumlara yol açar. Google bu karmaşıklığı ortadan kaldırmak için tek thread kuralını benimsedi.
16 Milisaniye Kuralı
UI thread'in neden bu kadar kritik olduğunu anlamak için ekran yenileme döngüsünü bilmek gerekir.
Çoğu Android cihaz ekranı saniyede 60 kez yeniler. Bu şu anlama gelir: Her frame için UI thread'in elinde yalnızca 16 milisaniye vardır. Bu süre içinde Layout hesaplamaları, View çizimleri ve tüm animasyon güncellemeleri tamamlanmak zorundadır.
Eğer UI thread 16 milisaniyeyi aşarsa bir frame atlanır. Kullanıcı bunu takılma, kasma ya da donma olarak hisseder. Buna jank denir ve mobil uygulamalarda kullanıcı memnuniyetsizliğinin en yaygın kaynaklarından biridir.
UI Thread'i Bloke Etmenin Tehlikesi
Şimdi kritik soruya gelelim: UI thread'de ağır bir iş yaparsanız ne olur?
Bir network isteği başlattığınızı düşünün. Bu istek tamamlanana kadar — belki 2 saniye, belki 10 saniye — UI thread bekler. Bu süre boyunca hiçbir animasyon güncellenmez, hiçbir dokunuş işlenmez, ekran tamamen donar.
Yeterince uzun süre — genellikle 5 saniye — UI thread bloke kalırsa Android, ANR (Application Not Responding) diyaloğunu gösterir. Kullanıcıya uygulamayı zorla kapatma seçeneği sunulur. Bu, bir uygulamanın kullanıcı gözündeki güvenilirliği için felakettir.
Çözüm: İşi Arka Plana Taşımak
UI thread'i korumak için ağır işler arka plan thread'lerine taşınmalıdır. Android bu ihtiyaç için çeşitli araçlar sunar.
Kotlin Coroutines modern Android geliştirmenin standart çözümüdür. Dispatchers.IO ile ağ ve disk işlemleri arka planda yürütülür, sonuç hazır olduğunda Dispatchers.Main ile UI thread'e geri dönülür. Kod sanki senkronmuş gibi yazılır ama arka planda tamamen asenkron çalışır.
WorkManager garanti edilmesi gereken arka plan görevleri içindir. Uygulama kapansa bile, cihaz yeniden başlasa bile tamamlanması gereken işler buraya aittir.
Foreground Service kullanıcının bildirim çubuğunda görmesi gereken devam eden işlemler içindir. Müzik çalma, aktif navigasyon, dosya indirme gibi senaryolar bu kategoriye girer.
Thread'ler Arası İletişim
Arka plan thread'i işini tamamladığında sonucu UI thread'e nasıl iletir?
Kotlin Coroutines bu geçişi withContext(Dispatchers.Main) ile son derece zarif biçimde çözer. Geleneksel yaklaşımda ise Handler ve Looper mekanizmaları kullanılırdı. UI thread'in bir Looper'ı vardır — bu Looper sürekli dönen ve gelen mesajları işleyen bir döngüdür. Başka thread'ler, Handler aracılığıyla bu döngüye mesaj göndererek UI güncellemelerini tetikleyebilir.
Geliştirici Perspektifinden Bakış
UI thread'i anlamak uygulamanızın performans profilini doğrudan şekillendirir.
Her network çağrısı, her veritabanı sorgusu, her dosya okuma işlemi arka planda çalışmak zorundadır. Bu kural istisnasız uygulanmalıdır. Android Studio'nun Profiler aracı UI thread üzerindeki yükü gerçek zamanlı gösterir ve hangi operasyonun ne kadar zaman aldığını net biçimde ortaya koyar.
Bir uygulamada ANR ya da jank yaşandığında ilk bakılacak yer daima UI thread'dir.