ANR Nedir, Nasıl Oluşur?
Sistemin Sabır Sınırı
Kullanıcı bir butona bastı. Hiçbir şey olmadı. Beş saniye geçti, on saniye geçti. Sonra ekranda bir dialog belirdi: "Uygulama yanıt vermiyor. Kapatmak ister misiniz?"
Bu mesajı gören kullanıcının uygulamaya olan güveni zedelenir. Büyük ihtimalle "Kapat" seçeneğine basar. Ve büyük ihtimalle bir daha o uygulamayı açmakta isteksiz davranır.
Bu senaryo yazılım dünyasında ANR — Application Not Responding olarak adlandırılır.
ANR Nedir?
ANR, Android sisteminin bir uygulamanın UI thread'inin belirli bir süre boyunca yanıt veremediğini tespit ettiğinde gösterdiği bir hata durumudur.
Kasma ile ANR arasındaki fark önemlidir. Kasma frame atlamaktır — kullanıcı bir yavaşlık hisseder ama uygulama çalışmaya devam eder. ANR ise uygulamanın tamamen donmasıdır — hiçbir etkileşim işlenemiyor, hiçbir animasyon ilerleyemiyor, sistem müdahale etmek zorunda kalıyor.
ANR Tetikleyici Koşullar
Android'in ANR üretmesi için belirli zaman sınırlarının aşılması gerekir.
En yaygın tetikleyici kullanıcı etkileşiminin yanıtsız kalmasıdır. Kullanıcı ekrana dokundu ama bu dokunuş 5 saniye içinde işlenemediyse ANR tetiklenir. Buton tıklaması, kaydırma, klavye girişi — herhangi bir etkileşimin bu süre içinde UI thread tarafından işlenememesi yeterlidir.
İkinci tetikleyici BroadcastReceiver'ların geç tamamlanmasıdır. Bir BroadcastReceiver'ın onReceive metodu ön planda 10 saniye, arka planda 60 saniye içinde tamamlanmak zorundadır. Bu süre aşılırsa ANR üretilir. BroadcastReceiver'lar UI thread üzerinde çalıştığından içlerinde ağır iş yapmak çift tehlike yaratır.
Üçüncü tetikleyici Service'lerin başlama ve bağlanma zaman aşımlarıdır. Service'in onCreate ve onStartCommand metodlarının da belirli süre sınırları vardır.
ANR'ın İçinde Ne Oluyor?
ANR bir anda ortaya çıkmaz. Sistem bunu tespit edebilmek için arka planda sürekli izleme yapar.
Android, UI thread'inin canlı olup olmadığını kontrol etmek için bir watchdog mekanizması kullanır. Bu mekanizma UI thread'e periyodik olarak küçük kontrol mesajları gönderir. UI thread bu mesajı belirtilen süre içinde işleyemezse — çünkü başka bir iş yapıyor ya da tamamen bloke olmuş — watchdog ANR'ı tetikler.
ANR tetiklendiğinde sistem birkaç şey yapar. Her thread'in o anki yığın izini (stack trace) kaydeder. Bu kayıt /data/anr/traces.txt dosyasına yazılır. Kullanıcıya dialog gösterilir. Ve eğer kullanıcı "Kapat" seçeneğini seçerse uygulama sonlandırılır.
En Sık ANR Nedenleri
Senkron ağ isteği UI thread'de yapıldığında sunucunun yanıt vermesini beklerken thread tamamen bloke kalır. Bu en naif ve en kaçınılabilir ANR nedenidir. Hiçbir ağ işlemi UI thread'de yapılmamalıdır.
Veritabanı kilitleri özellikle birden fazla thread'in aynı veritabanına eriştiği durumlarda ortaya çıkar. Bir thread yazmaya çalışırken başka bir thread okuma yapmak istiyorsa kilit çakışması yaşanabilir. UI thread bu kilidin açılmasını bekliyorsa ANR kaçınılmazdır.
Deadlock iki thread'in birbirini sonsuza kadar beklediği durumdur. Thread A, Thread B'nin serbest bırakmasını beklediği bir kilidi tutuyor. Thread B ise Thread A'nın serbest bırakmasını beklediği başka bir kilidi tutuyor. İkisi de ilerleyemez. UI thread bu kilitlerden birinin içindeyse ANR üretilir.
Senkron SharedPreferences işlemleri sıklıkla göz ardı edilen bir kaynaktır. apply() asenkron yazarken commit() senkron yazar ve işlem tamamlanana kadar UI thread'i bloke eder. Büyük SharedPreferences dosyalarında bu bekleme belirgin hale gelebilir.
Ana thread'de fazla iş daha sinsi bir nedendir. Tek başına küçük görünen ama üst üste yığılan işlemler toplamda 5 saniyeyi geçebilir. Büyük bir JSON'ı parse etmek, karmaşık bir hesaplama yapmak, büyük bir listeyi sıralamak — bunların her biri makul görünür ama onCreate içinde art arda yapıldığında sistem limitini aşabilir.
ANR Tespiti ve Analizi
ANR yaşandığında sistem traces.txt dosyasına yazar. Bu dosya ANR anındaki her thread'in stack trace'ini içerir. Doğru okunduğunda UI thread'in tam olarak nerede takıldığını gösterir.
Android Vitals, Google Play Console üzerinden gerçek kullanıcı verilerine dayalı ANR istatistiklerini sunar. Hangi cihazlarda, hangi Android versiyonlarında, hangi kod yollarında ANR yaşandığı bu panelden görülebilir.
StrictMode, geliştirme aşamasında UI thread'de yapılan disk ve ağ erişimlerini tespit eder ve loglar. Production'a çıkmadan önce bu tür ihlalleri yakalamak için son derece değerli bir araçtır. StrictMode.setThreadPolicy ile yapılandırılır ve ihlal tespit edildiğinde log basabilir, crash oluşturabilir ya da dialog gösterebilir.
ANR'dan Korunmanın Kuralları
Her zaman tekrar etmeye değer olan kural şudur: UI thread yalnızca UI işleri için kullanılır.
Ağ işlemleri, disk erişimi, veritabanı sorguları, karmaşık hesaplamalar — bunların tamamı arka plana taşınmalıdır. Kotlin Coroutines bu geçişi en temiz biçimde sağlar. viewModelScope.launch { withContext(Dispatchers.IO) { ... } } kalıbı UI thread'i korurken arka plan işini yürütür.
BroadcastReceiver'larda uzun işlemler yapmak gerekiyorsa işi bir Service'e ya da WorkManager'a devrederek onReceive metodunu hızlıca tamamlayın.
Ve her değişiklikten sonra orta segment cihazlarda test edin. ANR'lar güçlü geliştirici cihazlarında kendini göstermeyebilir.