ANR'ler

Bir Android uygulamasının kullanıcı arayüzü iş parçacığı çok uzun süre engellendiğinde "Uygulama yanıt vermiyor" (ANR) hatası tetiklenir. Uygulama ön plandaysa sistem, 1. şekilde gösterildiği gibi kullanıcıya bir iletişim kutusu gösterir. ANR iletişim kutusu, kullanıcıya uygulamayı kapanmaya zorlama fırsatı verir.

Kullanıcıya ANR iletişim kutusu gösterildiğinde.
Şekil 1. Kullanıcıya gösterilen ANR iletişim kutusu

ANR'ler sorun yaratır. Çünkü kullanıcı arayüzünü güncellemekten sorumlu olan uygulamanın ana iş parçacığı, kullanıcı giriş etkinliklerini işleyemez veya çizim yapamaz. Bu durum, kullanıcıların hayal kırıklığına uğramasına neden olur. Uygulamanın ana iş parçacığı hakkında daha fazla bilgi için İşlemlere ve iş parçacıklarına genel bakış başlıklı makaleyi inceleyin.

Aşağıdaki koşullardan biri gerçekleştiğinde uygulamanız için ANR tetiklenir:

  • Giriş gönderme zaman aşımına uğradı: Uygulamanız 5 saniye içinde bir giriş etkinliğine (ör. tuşa basma veya ekrana dokunma) yanıt vermediyse.
  • Hizmet yürütülüyor: Uygulamanız tarafından beyan edilen bir hizmet birkaç saniye içinde Service.onCreate ve Service.onStartCommand/Service.onBind yürütülmesini tamamlayamıyorsa.
  • Service.startForeground çağrılmıyor: Uygulamanız Context.startForegroundService kullanarak ön planda yeni bir hizmet başlatıyorsa ancak hizmet 5 saniye içinde startForeground işlevini çağırmıyorsa.
  • Niyet yayını: Bir BroadcastReceiver belirli bir süre içinde yürütülmeyi tamamlamadıysa. Uygulama ön planda herhangi bir etkinlik gösteriyorsa bu zaman aşımı 5 saniyedir.
  • JobScheduler etkileşimleri: Bir JobService birkaç saniye içinde JobService.onStartJob veya JobService.onStopJob'den dönmezse ya da kullanıcı tarafından başlatılan bir iş başlar ve uygulamanız JobService.onStartJob çağrıldıktan sonra birkaç saniye içinde JobService.setNotification'u çağırmazsa. Android 13 ve önceki sürümleri hedefleyen uygulamalarda ANR'ler sessizdir ve uygulamaya bildirilmez. Android 14 ve sonraki sürümleri hedefleyen uygulamalarda ise ANR'ler açıkça belirtilir ve uygulamaya bildirilir.

Uygulamanızda ANR'ler yaşanıyorsa sorunu teşhis etmek ve düzeltmek için bu belgedeki yönergeleri kullanabilirsiniz.

Sorunu tespit etme

Uygulamanızı zaten yayınladıysanız uygulamanızdaki ANR'lerle ilgili bilgileri görmek için Android vitals'ı kullanabilirsiniz. Sahadaki ANR'leri tespit etmek için başka araçlar da kullanabilirsiniz ancak Android vitals'ın aksine, üçüncü taraf araçların Android 10 ve önceki sürümlerdeki ANR'leri bildiremediğini unutmayın.

Android vitals

Android vitals, uygulamanızın ANR oranını izlemenize ve iyileştirmenize yardımcı olabilir. Android vitals, çeşitli ANR oranlarını ölçer:

  • ANR oranı: Günlük etkin kullanıcı sayınız arasında herhangi bir türde ANR yaşayanların yüzdesi.
  • Kullanıcı tarafından algılanan ANR oranı: Günlük etkin kullanıcı sayınız arasında, kullanıcı tarafından algılanan en az bir ANR yaşayanların yüzdesidir. Şu anda yalnızca türündeki Input dispatching timed out ANR'ler kullanıcı tarafından algılanan ANR olarak kabul edilmektedir.
  • Çoklu ANR oranı: Günlük etkin kullanıcı sayınız arasında en az iki ANR yaşayanların yüzdesi.

Günlük etkin kullanıcı, uygulamanızı tek bir günde tek bir cihazda (birden fazla oturumda) kullanan benzersiz bir kullanıcıdır. Tek bir günde uygulamanızı birden çok cihazda kullanan bir kullanıcı, o günün etkin kullanıcı sayısına her cihaz için bir kullanıcı olarak eklenir.

Kullanıcı tarafından algılanan ANR oranı önemli bir metriktir. Yani Google Play'de uygulamanızın keşfedilebilirliğini etkiler. Bu metriğin saydığı ANR'lerin her zaman kullanıcılar uygulamayla etkileşim halindeyken gerçekleşerek çok fazla aksamaya yol açması, bu metriği önemli kılar.

Play, bu metrik için iki kötü davranış eşiği belirlemiştir:

  • Genel olarak kötü davranış eşiği: Tüm cihaz modellerinde, günlük etkin kullanıcı sayısının en az% 0,47'si, kullanıcı tarafından algılanan ANR yaşamıştır.
  • Cihaz bazında kötü davranış eşiği: Günlük kullanıcıların en az% 8'i tek bir cihaz modeliyle ilişkili, kullanıcı tarafından algılanan ANR yaşamıştır.

Uygulamanız genel kötü davranış eşiğini aşarsa tüm cihazlarda bulunabilirliği azalabilir. Uygulamanız bazı cihazlarda cihaz başına kötü davranış eşiğini aşarsa bu cihazlardaki bulunabilirliği azalabilir ve mağaza girişinizde bir uyarı gösterilebilir.

Android vitals, uygulamanızda aşırı ANR'ler görüldüğünde Play Console üzerinden sizi uyarabilir.

Google Play'in Android vitals verilerini nasıl topladığı hakkında bilgi edinmek için Play Console belgelerine bakın.

ANR'leri teşhis etme

ANR'leri teşhis ederken dikkat etmeniz gereken bazı yaygın kalıplar vardır:

  • Uygulama, ana iş parçacığında G/Ç içeren yavaş işlemler yapıyor.
  • Uygulama, ana iş parçacığında uzun bir hesaplama yapıyor.
  • Ana iş parçacığı başka bir işleme senkron bağlayıcı araması yapıyor ve bu işlemin yanıt vermesi uzun sürüyor.
  • Ana iş parçacığı, başka bir iş parçacığında gerçekleşen uzun bir işlem için senkronize edilmiş bir blok beklenirken engellendi.
  • Ana iş parçacığı, işleminizde veya bir bağlayıcı çağrısı aracılığıyla başka bir iş parçacığıyla kilitlenmiş durumda. Ana ileti dizisi yalnızca uzun bir işlemin tamamlanmasını beklemiyor, aynı zamanda kilitlenme durumunda.

Aşağıdaki teknikler, ANR'lerinizin nedenini belirlemenize yardımcı olabilir.

HealthStats

HealthStats, toplam kullanıcı ve sistem süresi, CPU süresi, ağ, radyo istatistikleri, ekran açık/kapalı süresi ve uyandırma alarmlarını yakalayarak bir uygulamanın durumuyla ilgili metrikler sağlar. Bu sayede genel CPU kullanımını ve pilin boşalmasını ölçebilirsiniz.

Hata ayıkla

Debug, uygulamalardaki duraklama ve gecikmeleri belirlemek için izleme ve ayırma sayıları da dahil olmak üzere geliştirme sırasında Android uygulamalarını incelemenize yardımcı olur. Çalışma zamanı ve yerel bellek sayaçlarını, ayrıca belirli bir işlemin bellekte kapladığı yeri belirlemenize yardımcı olabilecek bellek metriklerini almak için Debug simgesini de kullanabilirsiniz.

ApplicationExitInfo

ApplicationExitInfo, Android 11 (API düzeyi 30) veya sonraki sürümlerde kullanılabilir ve uygulamanın çıkış nedenleri hakkında bilgi sağlar. Bu sorunlar arasında ANR'ler, düşük bellek, uygulama kilitlenmeleri, aşırı CPU kullanımı, kullanıcı kesintileri, sistem kesintileri ve çalışma zamanında istenen izin değişiklikleri yer alır.

Yüksek düzey modu

StrictMode, uygulamanızı geliştirirken ana iş parçacığında yanlışlıkla yapılan G/Ç işlemlerini bulmanıza yardımcı olur. StrictMode'ı uygulama veya etkinlik düzeyinde kullanabilirsiniz.

Arka plan ANR iletişim kutularını etkinleştirme

Android, yayın mesajının işlenmesi çok uzun süren uygulamalar için yalnızca cihazın Geliştirici seçenekleri bölümünde Tüm ANR'leri göster etkinse ANR iletişim kutularını gösterir. Bu nedenle, uygulama performans sorunları yaşasa bile arka plan ANR iletişim kutuları her zaman kullanıcıya gösterilmez.

Yeniden oluşturma ile ilgili performans sorunları

Yeniden oluşturma darboğazlarını takip etmek için Android Studio Profiler ve Layout Inspector'ı kullanın. Daha fazla bilgi için Jetpack Compose Performansı konusuna bakın.

İzleme dosyası çekme

Android mağazaları, ANR yaşadığında izleme bilgilerini kaydeder. Eski işletim sistemi sürümlerinde cihazda tek bir /data/anr/traces.txt dosyası bulunur. Daha yeni işletim sistemi sürümlerinde birden fazla /data/anr/anr_* dosyası bulunur. Android Debug Bridge (adb)'yi kök olarak kullanarak bir cihazdan veya emülatörden ANR izlerine erişebilirsiniz:

adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>

Cihazdaki Hata raporu al geliştirici seçeneğini veya geliştirme makinenizdeki adb bugreport komutunu kullanarak fiziksel bir cihazdan hata raporu alabilirsiniz. Daha fazla bilgi için Hata raporlarını yakalama ve okuma başlıklı makaleyi inceleyin.

Sorunları düzeltme

Sorunu belirledikten sonra, sık karşılaşılan sorunları düzeltmek için bu bölümdeki ipuçlarından yararlanabilirsiniz.

Ana iş parçacığında yavaş kod

Kodunuzda, uygulamanın ana iş parçacığının 5 saniyeden uzun süre boyunca meşgul olduğu yerleri belirleyin. Uygulamanızda şüpheli kullanım alanlarını bulun ve ANR'yi yeniden oluşturmaya çalışın.

Sık karşılaşılan bir sorun, doğrudan composable içinde uzun süren bir görevdir:

@Composable
fun BadList(rawStrings: List<String>) {
    // Math or sorting inside the composable runs on EVERY recomposition pass!
    val heavilyProcessedList = rawStrings
        .filter { it.isNotBlank() }
        .map { it.uppercase().reversed() }
        .map { it.computationallyHeavyFunction() }
.sortedBy { it.length }
    LazyColumn { items(sortedList) { Text(it) } }
}

// Modern Compose-first fix
@Composable
fun GoodList(viewModel: MyViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    // UI simply renders state; no heavy processing allowed here
    LazyColumn { items(uiState.sortedData) { Text(it) } }
}

Ana iş parçacığında G/Ç

Ana iş parçacığında G/Ç işlemleri yürütmek, ana iş parçacığında yavaş işlemlere yol açan yaygın bir nedendir ve bu durum ANR'lere neden olabilir. Geliştiriciler, Compose'da ilk durumu elde etmeye çalışırken genellikle yanlışlıkla disk okuma işlemlerini (ör. SharedPreferences veya veritabanı çağrıları) tetikler.

Uzun süren G/Ç işlemlerini kullanıcı arayüzü katmanından uzakta yürütün. withContext(Dispatchers.IO) kullanın veya daha da iyisi, ViewModel içinde veri katmanında Repository kullanın.

Kilitlenmeler

Bir iş parçacığı, gerekli bir kaynak başka bir iş parçacığı tarafından tutulduğu için bekleme durumuna girdiğinde kilitlenme oluşur. Bu iş parçacığı da ilk iş parçacığı tarafından tutulan bir kaynağı beklemektedir. Uygulamanın ana iş parçacığı bu durumdaysa ANR'lerin gerçekleşmesi olasıdır.

Kilitlenmeler, bilgisayar biliminde iyi çalışılmış bir olgudur ve kilitlenmeleri önlemek için kullanabileceğiniz kilitlenme önleme algoritmaları vardır.

Daha fazla bilgi için Wikipedia'daki Kilitlenme ve Kilitlenme önleme algoritmaları başlıklı makaleleri inceleyin.

Kotlin ve Compose kullanırken, UI iş parçacığını dondurmak yerine yürütme bağlamını askıya alarak iş parçacığı engellemeyi önlemek için temel kilitleri engellemeyen coroutine Mutex'leriyle (Mutex.withLock) değiştirebilirsiniz. Örneğin:

import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

// Modern non-blocking concurrency state architecture
class SecureDataRepository {
    private val mutex = Mutex()

    suspend fun safeUIAccess() {
        // If locked, the main thread suspends seamlessly, preventing an ANR
        mutex.withLock {
            performSafeOperation()
        }
    }
}

Yavaş yayın alıcılar

Uygulamalar, yayın alıcılar aracılığıyla yayın mesajlarına yanıt verebilir. Örneğin, uçak modunu etkinleştirebilir veya devre dışı bırakabilir ya da bağlantı durumundaki bir değişikliği bildirebilir. Bir uygulama yayın mesajını işlemek için çok uzun süre beklediğinde ANR oluşur.

ANR, aşağıdaki durumlarda oluşur:

  • Bir yayın alıcısı, onReceive yöntemini önemli bir süre içinde yürütmeyi tamamlamadı.
  • Bir yayın alıcısı goAsync işlevini çağırır ve PendingResult nesnesinde finish işlevini çağıramaz.

Uygulamanız, BroadcastReceiver öğesinin onReceive yönteminde yalnızca kısa işlemler gerçekleştirmelidir. Ancak uygulamanız bir yayın mesajı sonucunda daha karmaşık bir işlem gerektiriyorsa görevi ViewModel'ya (Kotlin eş yordamları, kapsamları ve görev dağıtıcılarının gücünden yararlanarak) ertelemelisiniz. Görevin en fazla birkaç saniye sürmesi bekleniyorsa herhangi bir tür durum bilgisi depolayıcıya veya birkaç saniyeden uzun sürmesi beklenen görevler için WorkManager'a ertelemelisiniz.

GameActivity

GameActivity kitaplığı, C veya C++ ile yazılmış oyun ve uygulamaların örnek olaylarında ANR sayısını azaltmıştır. Mevcut yerel etkinliğinizi GameActivity ile değiştirirseniz kullanıcı arayüzü iş parçacığının engellenmesini azaltabilir ve bazı ANR'lerin oluşmasını önleyebilirsiniz.

ANR'ler hakkında daha fazla bilgi için Uygulamanızın yanıt vermesini sağlama başlıklı makaleyi inceleyin. İş parçacıkları hakkında daha fazla bilgi için İş parçacığı oluşturma ile daha iyi performans başlıklı makaleyi inceleyin.

Ek kaynaklar

İçeriği görüntüleme