Bir Android uygulamasının kullanıcı arayüzü iş parçacığı çok uzun süre engellendiğinde sistem, "Uygulama yanıt vermiyor" (ANR) hatası gönderir. Bu sayfada, farklı türlerdeki ANR'ler, bunların nasıl teşhis edileceği ve düzeltmeyle ilgili öneriler açıklanmaktadır. Listelenen tüm varsayılan zaman aşımı süreleri AOSP ve Pixel cihazlar içindir. Bu süreler OEM'ye göre değişebilir.
ANR'lerin nedenini belirlerken sistem ve uygulama sorunlarını ayırt etmenin faydalı olduğunu unutmayın.
Sistem kötü durumdayken aşağıdaki sorunlar ANR'lere neden olabilir:
- Sistem sunucusundaki geçici sorunlar, genellikle hızlı olan bağlayıcı çağrılarının yavaşlamasına neden olur.
- Sistem sunucusuyla ilgili sorunlar ve cihazın yüksek yükü, uygulama iş parçacıklarının planlanmamasına neden olur.
Kullanabiliyorsanız sistem ve uygulama sorunlarını ayırt etmenin iyi bir yolu Perfetto izlerini kullanmaktır:
- Ana iş parçacığının planlanıp planlanmadığını görmek için Perfetto'daki iş parçacığı durumu izine bakarak iş parçacığının çalışıp çalışmadığını veya çalıştırılabilir olup olmadığını kontrol edin.
- Kilit çekişmesi gibi sorunlar için
system_serveriş parçacıklarına bakın. - Yavaş bağlayıcı çağrıları için varsa yanıt dizisine bakarak neden yavaş olduğunu görün.
Giriş gönderme zaman aşımı
Giriş dağıtımı ANR'leri, uygulamanın ana iş parçacığı bir giriş etkinliğine (ör. kaydırma veya tuşa basma) zamanında yanıt vermediğinde ortaya çıkar. Giriş gönderme zaman aşımları gerçekleştiğinde uygulama ön planda olduğundan, bu zaman aşımları neredeyse her zaman kullanıcı tarafından görülebilir ve etkilerini azaltmak çok önemlidir.
Varsayılan zaman aşımı süresi: 5 saniye.
Giriş dağıtımı ANR'leri genellikle ana iş parçacığındaki sorunlardan kaynaklanır. Ana ileti dizisi, kilit edinmeyi beklerken engellendiyse tutan ileti dizisi de dahil olabilir.
Giriş gönderme ANR'lerini önlemek için aşağıdaki en iyi uygulamaları izleyin:
- Ana iş parçacığında engelleme veya uzun süren işlemler gerçekleştirmeyin. Ana iş parçacığındaki yanlışlıkla yapılan etkinlikleri yakalamak için
StrictModekullanmayı deneyin. - Ana iş parçacığı ile diğer iş parçacıkları arasındaki kilit çekişmesini en aza indirin.
- Ana iş parçacığında kullanıcı arayüzü dışındaki işleri (ör. yayınları işleme veya hizmetleri çalıştırma) en aza indirin.
Genel nedenler
Giriş gönderme ANR'lerinin yaygın nedenleri ve önerilen düzeltmeler aşağıda verilmiştir.
| Neden | Ne olur? | Önerilen düzeltmeler |
|---|---|---|
| Bağlayıcı çağrısı yavaş | Ana iş parçacığı uzun bir senkron bağlayıcı çağrısı yapıyor. | API'nin sahibiyseniz aramayı ana iş parçacığından çıkarın veya aramayı optimize etmeyi deneyin. |
| Çok sayıda ardışık bağlayıcı çağrısı | Ana iş parçacığı, çok sayıda ardışık senkron bağlayıcı çağrısı yapıyor. | Bağlayıcı çağrılarını sıkı bir döngüde yapmayın. |
| G/Ç'yi engelleme | Ana iş parçacığı, veritabanı veya ağ erişimi gibi engelleyici G/Ç çağrısı yapıyor. | Tüm engelleme G/Ç'lerini ana ileti dizisinden taşıyın. |
| Kilit anlaşmazlığı | Ana iş parçacığı, kilit edinmeyi beklerken engellendi. | Ana iş parçacığı ile diğer iş parçacığı arasındaki kilit çekişmesini azaltın. Diğer iş parçacığındaki yavaş kodu optimize edin. |
| Pahalı çerçeve | Tek bir karede çok fazla öğe oluşturulması, ciddi takılmaya neden olur. | Çerçeveyi oluşturmak için daha az çalışın. n2 algoritmalarını kullanmayın. Kaydırma veya sayfalama gibi işlemler için verimli bileşenler kullanın. Örneğin, Jetpack Paging kitaplığı. |
| Başka bir bileşen tarafından engellendi | Yayın alıcısı gibi farklı bir bileşen çalışıyor ve ana iş parçacığını engelliyor. | Kullanıcı arayüzüyle ilgili olmayan işleri mümkün olduğunca ana iş parçacığının dışına taşıyın. Yayın alıcılarını farklı bir iş parçacığında çalıştırın. |
| GPU takılması | GPU askısı, oluşturmanın engellenmesine ve dolayısıyla giriş dağıtımı ANR'sine neden olan bir sistem veya donanım sorunudur. | Ne yazık ki, genellikle uygulama tarafında düzeltme olmaz. Mümkünse sorun gidermek için donanım ekibiyle iletişime geçin. |
Hata ayıklama
Google Play Console veya Firebase Crashlytics'te ANR kümesi imzasını inceleyerek hata ayıklamaya başlayın. Küme genellikle ANR'ye neden olduğundan şüphelenilen en üstteki çerçeveleri içerir.
Aşağıdaki akış şemasında, giriş zaman aşımı dağıtımı ANR'sinin nedeninin nasıl belirleneceği gösterilmektedir.
Play vitals, bu yaygın ANR nedenlerinden bazılarını tespit edebilir ve hatalarını ayıklamanıza yardımcı olabilir. Örneğin, önemli veriler kilitlenme anlaşmazlığı nedeniyle ANR oluştuğunu tespit ederse ANR Analizleri bölümünde sorunu ve önerilen düzeltmeyi özetleyebilir.
Odaklanılmış pencere yok
Dokunma gibi etkinlikler, isabet testi temelinde doğrudan ilgili pencereye gönderilirken tuşlar gibi etkinlikler için hedef gerekir. Bu hedef, odaklanılan pencere olarak adlandırılır. Ekran başına yalnızca bir odaklanmış pencere vardır ve bu pencere genellikle kullanıcının o anda etkileşimde bulunduğu penceredir. Odaklanmış bir pencere bulunamazsa giriş, no-focused-window ANR (Odaklanmış pencere yok ANR) hatasına neden olur. Odaklanılmamış pencere ANR'si, giriş dağıtımı ANR'sidir.
Varsayılan zaman aşımı süresi: 5 saniye.
Genel nedenler
Odaklanılmamış pencere ANR'leri genellikle aşağıdaki sorunlardan birinden kaynaklanır:
- Uygulama çok fazla işlem yapıyor ve ilk kareyi çizmek için çok yavaş.
- Ana pencereye odaklanılamıyor. Bir pencere
FLAG_NOT_FOCUSABLEile işaretlenirse kullanıcı, pencereye tuş veya düğme etkinlikleri gönderemez.
Kotlin
override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) window.addFlags(WindowManager.LayoutParams.FLAG_FLAG_NOT_FOCUSABLE) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); }
Yayın alıcı zaman aşımı
Yayın alıcı ANR'si, yayın alıcı bir yayını zamanında işlemediğinde meydana gelir. Senkron alıcılar veya goAsync() işlevini çağırmayan alıcılar için zaman aşımı, onReceive() işlevinin zamanında tamamlanmadığı anlamına gelir. goAsync() işlevini çağıran veya eşzamansız alıcılar için zaman aşımı, PendingResult.finish() işlevinin zamanında çağrılmadığı anlamına gelir.
Yayın alıcısı ANR'leri genellikle şu ileti dizilerinde meydana gelir:
- Sorun yavaş uygulama başlatma ise ana ileti dizisi.
- Sorun yavaş
onReceive()kod ise yayın alıcısını çalıştıran iş parçacığı. - Sorun yavaş
goAsync()yayın kodundan kaynaklanıyorsa yayın çalışanı iş parçacıkları.
Yayın alıcısı ANR'lerini önlemek için aşağıdaki en iyi uygulamaları kullanın:
- Uygulama, yayını işlemek için başlatıldığında uygulama başlangıcı, ANR zaman aşımına dahil edildiğinden hızlı olmalıdır.
goAsync()kullanılıyorsaPendingResult.finish()'nin hızlıca çağrıldığından emin olun. Bu, senkron yayın alıcılarla aynı ANR zaman aşımına tabidir.goAsync()kullanılıyorsa çalışan iş parçacıklarının diğer uzun süren veya engelleyici işlemlerle paylaşılmadığından emin olun.- Ana iş parçacığında çalışan kullanıcı arayüzü kodunun engellenmesini önlemek için yayın alıcılarını ana olmayan bir iş parçacığında çalıştırmak üzere
registerReceiver()kullanmayı düşünebilirsiniz.
Zaman aşımı süreleri
Yayın alma zaman aşımı süreleri, ön plan amacının işaretinin ayarlanıp ayarlanmadığına ve platform sürümüne bağlıdır.
| Amaç türü | Android 13 ve önceki sürümler | Android 14 ve sonraki sürümler |
|---|---|---|
Ön plan öncelikli intent ( |
10 saniye |
İşlemin CPU'ya aç olup olmadığına bağlı olarak 10-20 saniye |
Arka plan önceliği intent'i ( |
60 saniye |
İşlemin CPU'ya aç olup olmamasına bağlı olarak 60-120 saniye |
FLAG_RECEIVER_FOREGROUND işaretinin ayarlanıp ayarlanmadığını anlamak için ANR konusundaki "flg=" ifadesini bulun ve 0x10000000 işaretinin varlığını kontrol edin. Bu bit ayarlanırsa niyetin FLAG_RECEIVER_FOREGROUND ayarlanmış demektir ve bu nedenle zaman aşımı daha kısadır.
Kısa yayın zaman aşımı (10-20 saniye) içeren örnek ANR konusu:
Broadcast of Intent { act=android.inent.action.SCREEN_ON flg=0x50200010 }
Uzun yayın zaman aşımı (60-120 saniye) içeren örnek ANR konusu:
Broadcast of Intent { act=android.intent.action.TIME_SET flg=0x25200010 }
Yayın süreleri nasıl ölçülür?
Yayın süresi ölçümü, yayın system_server kaynağından uygulamaya gönderildiğinde başlar ve uygulama yayını işlemeyi bitirdiğinde sona erer. Uygulama işlemi zaten çalışmıyorsa ANR zaman aşımı süresi içinde soğuk başlatma da yapması gerekir. Bu nedenle, yavaş uygulama başlatma, yayın alıcısı ANR'lerine neden olabilir.
Aşağıdaki şekilde, yayın alıcısı ANR zaman çizelgesinin belirli uygulama süreçleriyle nasıl uyumlu olduğu gösterilmektedir.
ANR zaman aşımı ölçümü, alıcı yayını işlemeyi bitirdiğinde sona erer. Bunun tam olarak ne zaman gerçekleşeceği, alıcının senkron mu yoksa asenkron mu olduğuna bağlıdır.
- Eşzamanlı alıcılar için ölçüm,
onReceive()döndüğünde durur. - Asenkron alıcılar için ölçüm,
PendingResult.finish()çağrıldığında durur.
Genel nedenler
Yayın alıcısı ANR'lerinin yaygın nedenleri ve önerilen düzeltmeler aşağıda verilmiştir.
| Neden | Uygulandığı yer | Ne oldu? | Önerilen düzeltme |
|---|---|---|---|
| Yavaş uygulama başlatma | Tüm alıcılar | Uygulamanın baştan başlatılması çok uzun sürdü. | Yavaş uygulama başlatmayı optimize edin. |
onReceive() planlanmadı | Tüm alıcılar | Yayın alıcısı iş parçacığı başka işlerle meşguldü ve onReceive() yöntemini başlatamadı. | Alıcı iş parçacığında uzun süren görevler gerçekleştirmeyin (veya alıcıyı özel iş parçacığına taşımayın). |
onReceive() yavaş | Tüm alıcılar, ancak esas olarak eşzamanlı olanlar | onReceive() yöntemi başlatıldı ancak engellendi veya yavaş olduğu için zamanında tamamlanmadı. | Yavaş alıcı kodunu optimize edin. |
| Eşzamansız alıcı görevleri planlanmadı | goAsync()
alıcılar | onReceive() yöntemi, çalışmayı engellenmiş bir çalışan iş parçacığı havuzunda yürütmeye çalıştığı için çalışma hiç başlamadı. |
Yavaş veya engelleyici çağrıları optimize edin ya da yayın çalışanları ile diğer uzun süren görevler için farklı iş parçacıkları kullanın. |
| Çalışanlar yavaş veya engellenmiş | goAsync() alıcılar |
Yayın işlenirken çalışan iş parçacığı havuzunda bir yerde engelleme veya yavaş işlem oluştu. Bu nedenle, PendingResult.finish
zamanında aranmadı. | Yavaş async alıcı kodunu optimize edin. |
PendingResult.finish adlı kişiyi aramayı unuttum |
goAsync() alıcılar |
Kod yolunda finish() işlevi eksik. |
finish() öğesinin her zaman çağrıldığından emin olun. |
Hata ayıklama
Küme imzasına ve ANR raporuna göre, alıcının üzerinde çalıştığı iş parçacığını ve ardından eksik olan veya yavaş çalışan kodu bulabilirsiniz.
Aşağıdaki akış çizelgesinde, bir yayın alıcısı ANR'sinin nedeninin nasıl belirleneceği gösterilmektedir.
Alıcı kodunu bulma
Google Play Console, ANR imzasında alıcı sınıfını ve yayın amacını gösterir. Aşağıdakileri kontrol edin:
cmp=<receiver class>act=<broadcast_intent>
Aşağıda bir yayın alıcısı ANR imzası örneği verilmiştir:
com.example.app.MyClass.myMethod
Broadcast of Intent { act=android.accounts.LOGIN_ACCOUNTS_CHANGED
cmp=com.example.app/com.example.app.MyAccountReceiver }
onReceive() yöntemini çalıştıran iş parçacığını bulun.
Özel bir işleyici belirtmek için Context.registerReceiver kullanıyorsanız bu işleyiciyi çalıştıran iş parçacığıdır. Aksi takdirde, ana ileti dizisidir.
Örnek: Eşzamansız alıcı görevleri planlanmıyor
Bu bölümde, yayın alıcısı ANR'sinin nasıl hata ayıklanacağına dair bir örnek açıklanmaktadır.
ANR imzası aşağıdaki gibi görünüyor:
com.example.app.MyClass.myMethod
Broadcast of Intent {
act=android.accounts.LOG_ACCOUNTS_CHANGED cmp=com.example.app/com.example.app.MyReceiver }
İmzaya göre yayın amacı android.accounts.LOG_ACCOUNTS_CHANGED ve alıcı sınıfı com.example.app.MyReceiver.
Alıcı kodundan, "BG Thread
[0,1,2,3]" iş parçacığı havuzunun bu yayını işlemek için ana işi yaptığını belirleyebilirsiniz. Yığın dökümlerine baktığınızda, dört arka plan (BG) iş parçacığının da aynı düzene sahip olduğunu görebilirsiniz: getDataSync engelleme çağrısı çalıştırıyorlar. Tüm arka plan iş parçacıkları meşgul olduğundan yayın zamanında işlenemedi ve bu durum ANR'ye yol açtı.
BG Thread #0 (tid=26) Waiting
at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture:563)
at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture:68)
at com.example.app.getDataSync(<MyClass>:152)
...
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.android.libraries.concurrent.AndroidExecutorsModule.lambda$withStrictMode$5(AndroidExecutorsModule:451)
at com.google.android.libraries.concurrent.AndroidExecutorsModule$$ExternalSyntheticLambda8.run(AndroidExecutorsModule:1)
at java.lang.Thread.run(Thread.java:1012)
at com.google.android.libraries.concurrent.ManagedPriorityThread.run(ManagedPriorityThread:34)
There are several approaches to fix the issue:
- Find out why
getDataSyncis slow and optimize. - Don't run
getDataSyncon all four BG threads. - More generally, ensure that the BG thread pool isn't saturated with long-running operations.
- Use a dedicated thread pool for
goAsyncworker tasks. - Use an unbounded thread pool instead of the bounded BG thread pool
Example: slow app startup
A slow app startup can cause several types of ANRs, especially broadcast
receiver and execute service ANRs. The cause of an
ANR is likely slow app startup if you see ActivityThread.handleBindApplication
in the main thread stacks.
Execute service timeout
An execute service ANR happens when the app's main thread doesn't start a
service in time. Specifically, a service doesn't finish executing
onCreate() and onStartCommand() or onBind() within the
timeout period.
Default timeout period: 20 seconds for foreground service; 200 seconds for
background service. The ANR timeout period includes the app cold start, if
necessary, and calls to onCreate(), onBind(), or onStartCommand().
To avoid execute service ANRs, follow these general best practices:
- Make sure that app startup is fast, since it's counted in the ANR timeout if the app is started to run the service component.
- Make sure that the service's
onCreate(),onStartCommand(), andonBind()methods are fast. - Avoid running any slow or blocking operations on the main thread from other components; these operations can prevent a service from starting quickly.
Common causes
The following table lists common causes of execute service ANRs and suggested fixes.
| Cause | What | Suggested fix |
|---|---|---|
| Slow app startup | The app takes too long to perform a cold start. | Optimize slow app start. |
Slow onCreate(), onStartCommand(), or
onBind() |
The service component's onCreate(),
onStartCommand(), or onBind() method takes too long to
execute on the main thread. |
Optimize slow code. Move slow operations off the critical path where possible. |
Not scheduled (main thread blocked before onStart()) |
The app's main thread is blocked by another component before the service can be started. | Move other component's work off the main thread. Optimize other component's blocking code. |
How to debug
From the cluster signature and ANR report in Google Play Console or Firebase Crashlytics, you can often determine the cause of the ANR based on what the main thread is doing.
The following flow chart describes how to debug an execute service ANR.
If you've determined that the execute service ANR is actionable, follow these steps to help resolve the issue:
Find the service component class in the ANR signature. In Google Play Console, the service component class is shown in the ANR signature. In the following example ANR details, it's
com.example.app/MyService.com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly Executing service com.example.app/com.example.app.MyServiceDetermine whether the slow or block operation is part of app startup, the service component, or elsewhere by checking for the following important function call(s) in the main threads.
Function call(s) in main thread stacks What it means android.app.ActivityThread.handleBindApplicationApp was starting up, so the ANR was caused by slow app start. <ServiceClass>.onCreate()
[...]
android.app.ActivityThread.handleCreateService
Service was being created, so the ANR was likely caused by slow onCreate()code.<ServiceClass>.onBind()
[...]
android.app.ActivityThread.handleBindService
Service was being bound, so the ANR was likely caused by slow onBind()code.<ServiceClass>.onStartCommand()
[...]
android.app.ActivityThread.handleServiceArgs
Service was being started, so the ANR was likely caused by slow onStartCommand()code.For example, if the
onStartCommand()method in theMyServiceclass is slow, the main threads will look like this:at com.example.app.MyService.onStartCommand(FooService.java:25) at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4820) at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(unavailable:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2289) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:205) at android.os.Looper.loop(Looper.java:294) at android.app.ActivityThread.main(ActivityThread.java:8176) at java.lang.reflect.Method.invoke(Native method:0)Önemli işlev çağrılarından herhangi birini göremiyorsanız başka olasılıklar da vardır:
- Hizmet çalışıyor veya kapatılıyor. Bu durumda yığınlar çok geç alınır. Bu durumda, ANR'yi yanlış pozitif olarak değerlendirip yoksayabilirsiniz.
- Yayın alıcısı gibi farklı bir uygulama bileşeni çalışıyordur. Bu durumda, ana iş parçacığı bu bileşende engellenmiş olabilir ve hizmetin başlatılması engellenir.
Önemli bir işlev çağrısı görüyorsanız ve ANR'nin genel olarak nerede gerçekleştiğini belirleyebiliyorsanız yavaş işlemi bulmak için ana iş parçacığı yığınlarının geri kalanını kontrol edin ve bu işlemi optimize edin veya kritik yoldan kaldırın.
- Uygulama, içerik sağlayıcıyı çalıştırmak için başlatıldığında uygulama başlatma işleminin hızlı olduğundan emin olun. Bu işlem, ANR zaman aşımı süresine dahil edilir.
- İçerik sağlayıcı sorgularının hızlı olduğundan emin olun.
- Uygulamanın bağlayıcı iş parçacıklarının tümünü engelleyebilecek çok sayıda eşzamanlı engelleme bağlayıcı çağrısı yapmayın.
- Sessiz kullanıcı arayüzü donmaları: Uygulamanın kullanıcı arayüzü, kullanıcı girişine yanıt vermeyi durdurur.
- Kilitlenmeler: Uygulama,
illegalStateExceptionile kilitlenebilir. - ANR'ler: Sistem, ANR zaman aşımını tetikleyebilir.
- Çapraz Geçişleri Planlama:
ViewRootImpl, kullanıcı arayüzü iş parçacığınınMessageQueue'ına bir senkronizasyon engeli göndererek çapraz geçiş (düzen ve çizim geçişi) planlar. Bu engel, kullanıcı arayüzü düzeninin öncelikli olması için normal ileti işlemeyi duraklatır. - Yarışma durumu: Birden fazla iş parçacığı aynı anda bir görünümü geçersiz kılmaya çalıştığında bu geçişi planlamak için yarışırlar. Her iki iş parçacığı da senkronizasyon engeli'ni başarıyla ekleyebilir ancak çerçeve yalnızca birinin jetonunu saklar.
- Kullanıcı arayüzü dondurma: Geçiş yürütüldüğünde yalnızca tek bir kaydedilmiş bariyer kaldırılır. İkincil, "sızdırılmış" engeller süresiz olarak kuyrukta kalır ve kullanıcı arayüzü iş parçacığının eşzamanlı mesajları işlemesini kalıcı olarak engeller.
- Yalnızca görünüm hiyerarşisini oluşturduğunuz ileti dizisinde
Viewnesnelerle etkileşim kurun. Bu etkileşimler arasındawidthveyaheightgibi özellikleri okuma ya daTextView's textgibi özellikleri ayarlama yer alır. Bu, neredeyse her zaman ana veya kullanıcı arayüzü ileti dizisidir. - Görünümlere erişirken kullanıcı arayüzü iş parçacığında çalıştığınızı garanti edemiyorsanız bunu yapmanın güvenli olmadığını varsayın. Örneğin, arka plan çalışması için
CoroutineskullanıyorsanızViewnesnelerini değiştirmeden önce ana dağıtıcıya geçmeniz gerekir. ContextCompat#getMainExecutor(android.content.Context)View.post(Runnable)Activity.runOnUiThread(Runnable)- Uygulamanızın hata ayıklanabilir bir sürümünü Android 17 veya sonraki bir sürümün yüklü olduğu bir cihaza yükleyin.
- Cihazınızın Ayarlar uygulamasını açın ve Sistem > Gelişmiş > Geliştirici seçenekleri > Uygulama Uyumluluğuyla İlgili Değişiklikler'e gidin.
- Listeden uygulamanızı seçin.
- Değişiklik listesinde
ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APISanahtarını bulup etkinleştirin. - Telemetri ve İzleme: Bu dinleyici, bir View API'si yanlış iş parçacığından çağrıldığında uygulamanızın geri çağırma işlemleri almasına olanak tanır. Böylece telemetriyi kaydetmek ve hataları izlemek kolaylaşır.
- Satır İçi Yürütme: İşleyici satır içinde çağrılır. Bu sayede, ihlal gerçekleştiği anda tam yığın izlemeyi (stack trace) yakalayıp inceleyebilirsiniz.
- Sistem genelinde sorun. İşlem, sistemin aşırı yüklenmesi veya sistem sunucusundaki bir sorun nedeniyle planlanmadı.
- Geç yığın dökümü. ANR tetiklenmesi ile yığınların dökülmesi arasındaki kısa süre içinde iş parçacığı kurtarılır. Android 13'teki Pixel'lerde gecikme süresi yaklaşık 100 ms'dir ancak 1 saniyeyi aşabilir. Android 14'teki Pixel cihazlarda gecikme genellikle 10 ms'nin altındadır.
- İleti dizisinin yanlış ilişkilendirilmesi. ANR imzası oluşturmak için kullanılan iş parçacığı, ANR'ye neden olan asıl yanıt vermeyen iş parçacığı değildi.
- İş parçacığı oluşturma ihlalini görüntüleyin. Uygulamanız bir arka plan iş parçacığında görünümü değiştirirse görünümün iç kısımlarında, kullanıcı arayüzü iş parçacığı görevlerinin çalışmasını engelleyen bir yarış durumu tetiklenebilir.
- Aşırı sistem yükü: Yanıt vermeme durumunun temel nedeni olarak sistem genelinde CPU, bellek veya G/Ç kıtlığı gibi genel cihaz kaynak baskısını değerlendirin.
- İş parçacığı yanlış ilişkilendirmesi: Çalışan ve bağlayıcı iş parçacıklarını kilitlenmeler, ana iş parçacığını etkileyen kilit çekişmesi veya eşzamansız bileşenleri (ör.
goAsync()) işleyen askıda kalan arka plan iş parçacıkları açısından denetleyin. - İş parçacığı ihlallerini görüntüleme: Arka plan iş parçacıklarını, yasa dışı kullanıcı arayüzü görünümü hiyerarşisi değişiklikleri için tarayın. Bu değişiklikler, MessageQueue'da bir senkronizasyon engelinin yetim kalmasına ve tüm eşzamanlı mesajların kalıcı olarak engellenmesine neden olabilir.
- Yığını almak çok uzun sürüyor ve zaman aşımına uğruyor.
- Yığınlar alınmadan önce süreç sonlandırıldı.
Hizmetler hakkında daha fazla bilgi için aşağıdaki sayfalara bakın:
İçerik sağlayıcı yanıt vermiyor
Uzak bir içerik sağlayıcı, bir sorguya yanıt vermek için zaman aşımı süresinden daha uzun süre beklerse ve sonlandırılırsa içerik sağlayıcı ANR'si oluşur.
Varsayılan zaman aşımı süresi: İçerik sağlayıcı tarafından ContentProviderClient.setDetectNotResponding kullanılarak belirtilir. ANR zaman aşımı süresi, uzak bir içerik sağlayıcı sorgusunun çalışması için gereken toplam süreyi içerir. Bu süre, uzak uygulama zaten çalışmıyorsa soğuk başlatma süresini de kapsar.
İçerik sağlayıcı ANR'lerini önlemek için aşağıdaki en iyi uygulamaları izleyin:
Genel nedenler
Aşağıdaki tabloda, içerik sağlayıcı ANR'lerinin yaygın nedenleri ve önerilen düzeltmeler listelenmektedir.
| Neden | Ne olur? | Sinyal | Önerilen düzeltme |
|---|---|---|---|
| İçerik sağlayıcı sorgusunun yavaş olması | İçerik sağlayıcının yürütmesi çok uzun sürüyor veya engelleniyor. | android.content.ContentProvider$Transport.query çerçevesi, bağlayıcı iş parçacığında yer alıyor. |
İçerik sağlayıcı sorgusunu optimize edin. Binder iş parçacığını neyin engellediğini öğrenin. |
| Yavaş uygulama başlatma | İçerik sağlayıcının uygulamasının başlatılması çok uzun sürüyor. | ActivityThread.handleBindApplication çerçevesi ana iş parçacığındadır. |
Uygulama başlatma işlemini optimize edin. |
| Bağlayıcı iş parçacığı tükenmesi: Tüm bağlayıcı iş parçacıkları meşgul | Tüm bağlayıcı iş parçacıkları diğer eşzamanlı isteklere hizmet etmekle meşgul olduğundan içerik sağlayıcı bağlayıcı çağrısı çalıştırılamıyor. | Uygulama başlatılmıyor, tüm bağlayıcı iş parçacıkları meşgul ve içerik sağlayıcı çalışmıyor. | Bağlayıcı dişlerindeki yükü azaltır. Yani, daha az sayıda senkron giden bağlayıcı çağrısı yapın veya gelen çağrıları işlerken daha az iş yapın. |
Hata ayıklama
Google Play Console veya Firebase Crashlytics'teki küme imzası ve ANR raporunu kullanarak bir içerik sağlayıcı ANR'sini ayıklamak için ana iş parçacığının ve bağlayıcı iş parçacıklarının ne yaptığına bakın.
Aşağıdaki akış şeması, içerik sağlayıcı ANR'sinin nasıl ayıklanacağını açıklamaktadır:
Aşağıdaki kod snippet'inde, yavaş içerik sağlayıcı sorgusu nedeniyle engellendiğinde bağlayıcı iş parçacığının nasıl göründüğü gösterilmektedir. Bu durumda, içerik sağlayıcı sorgusu bir veritabanı açılırken kilit beklemektedir.
binder:11300_2 (tid=13) Blocked
Waiting for osm (0x01ab5df9) held by at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers:182)
at com.example.app.MyClass.blockingGetOpenDatabase(FooClass:171)
[...]
at com.example.app.MyContentProvider.query(MyContentProvider.java:915)
at android.content.ContentProvider$Transport.query(ContentProvider.java:292)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:107)
at android.os.Binder.execTransactInternal(Binder.java:1339)
at android.os.Binder.execTransact(Binder.java:1275)
Aşağıdaki kod snippet'i, uygulamanın yavaş başlatılması nedeniyle ana iş parçacığı engellendiğinde nasıl göründüğünü gösterir. Bu durumda, uygulama başlangıcı, Dagger ilk kullanıma hazırlama sırasında kilit çekişmesi nedeniyle yavaş olur.
main (tid=1) Blocked
[...]
at dagger.internal.DoubleCheck.get(DoubleCheck:51)
- locked 0x0e33cd2c (a qsn)at dagger.internal.SetFactory.get(SetFactory:126)
at com.myapp.Bar_Factory.get(Bar_Factory:38)
[...]
at com.example.app.MyApplication.onCreate(DocsApplication:203)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(unavailable:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2235)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8170)
at java.lang.reflect.Method.invoke(Native method:0)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Yavaş iş yanıtı
Yavaş iş yanıtı ANR'si, uygulamanın JobService.onStartJob() veya JobService.onStopJob() öğesine yanıt vermesi ya da JobService.setNotification() kullanarak bildirim sağlaması çok uzun sürdüğünde meydana gelir. Bu durum, uygulamanın ana iş parçacığının başka bir işlem yaparken engellendiğini gösterir.
Sorun JobService.onStartJob() veya JobService.onStopJob() ile ilgiliyse ana iş parçacığında neler olduğuna bakın. JobService.setNotification() ile ilgili bir sorun varsa en kısa sürede aradığınızdan emin olun.
Bildirimi sağlamadan önce çok fazla işlem yapmayın.
İleti Dizisi Oluşturma İhlalini Görüntüleme
Uygulamanız bir görünümü arka plan iş parçacığında değiştirirse görünüm hiyerarşisinin dahili durumunda yarış durumu tetiklenebilir. Bu ihlal, ana (UI) iş parçacığının senkron mesajları yürütmesini engelleyerek kritik kararlılık sorunlarına yol açabilir:
Bu iş parçacığı ihlali, ana iş parçacığının boşta göründüğü ANR yığın izlemelerinin (ör. "nativePollOnce" veya "main thread idle" içinde yakalanan) temel nedenlerinden biridir.
Senkronizasyon engeli sızıntısı
Görünümler, durumları değiştirilerek (örneğin, TextView.setText, View.setVisibility çağrılarak) dolaylı olarak veya View.invalidate ya da View.requestLayout çağrılarak doğrudan geçersiz kılınabilir. Bir görünüm geçersiz kılındığında,
ViewRootImpl kullanıcı arayüzü durumunu güncellemek için ölçüm, düzen ve çizim işlemlerini gerçekleştirmek üzere bir geçiş planlar.
Bu nedenle kullanıcı arayüzü donar. MessageQueue, sızdırılan engellerin ötesindeki senkron iletileri işleyemediğinden ana iş parçacığı boşta durma durumuna girer. Bu sorun genellikle yığın izinde nativePollOnce ile ANR olarak ortaya çıkar.
Görünüm dizisi oluşturma ihlallerini önlemek için aşağıdaki en iyi uygulamaları izleyin:
lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { val data = myRepository.getData() withContext(Dispatchers.Main) { // Switch context to Main myTextView.text = data.title } }
Android, en iyi uygulamaları uygulamanıza yardımcı olmak için kullanıcı arayüzü iş parçacığına diğer iş parçacıklarından erişmenin çeşitli yollarını sunar:
Popüler resim yükleyiciler, reaktif uzantı çerçeveleri, etkinlik veri yolu kitaplıkları ve diğer iş parçacığı çözümleri genellikle ana iş parçacığında belirli etkinlikleri gözlemlemenin yollarını sunar. Bu, görünümlerin durumunu alması ve ayarlaması gereken gözlemciler ve etkinlik işleyiciler için yararlıdır.
Hata ayıklama
Android 17, geliştirme sırasında görünüm iş parçacığı ihlallerini belirlemenize, izlemenize ve çözmenize yardımcı olacak yeni araçlar sunar.
1. Uyumluluk çerçevesi araçları
Uyumluluk çerçevesi araçları, uygulama geliştiricilerin geliştirici seçeneklerini veya ADB'yi kullanarak davranış değişikliklerini tek tek etkinleştirmesine ve devre dışı bırakmasına olanak tanır. Aşağıdaki adımları uygulayarak görünümdeki iş parçacığı ihlali davranış değişikliklerini etkinleştirebilir veya devre dışı bırakabilirsiniz:
İşareti ADB kullanarak da açıp kapatabilirsiniz:
$ adb shell am compat enable ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS <your.package.name>
$ adb shell am compat disable ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS <your.package.name>
Bu işaretin etkinleştirilmesi, bir View API'si yanlış iş parçacığından her çağrıldığında uygulamanın istisna oluşturmasına ve kilitlenmesine neden olur. Bu sayede, görünüm iş parçacığı ihlali sorunlarını yakalamanıza ve düzeltmenize yardımcı olur.
2. CalledFromWrongThreadListener API'si
Ayrıca, uygunsuz iş parçacığı erişimini programatik olarak algılamak için genel View#registerCalledFromWrongThreadListener API'sini de uygulayabilirsiniz.
android {
//...
compileSdk = 37
}
val listener = object : View.CalledFromWrongThreadListener { override fun onCalledFromWrongThread() { // Handle the issue, e.g. crash if this is a dev build, or log an event // e.g. Log.d(TAG, "CalledFromWrongThread: ${Exception().stackTraceToString()}") // Unregister the listener to avoid redundant notifications for the same issue View.unregisterCalledFromWrongThreadListener(this) } } View.registerCalledFromWrongThreadListener(listener)
nativePollOnce
ANR yığınlarında "nativePollOnce" veya "message queue idle" çerçevesini görüyorsanız bu genellikle yanıt vermediğinden şüphelenilen iş parçacığının aslında boşta olduğu ve looper mesajlarını beklediği anlamına gelir. Google Play Console'da ANR ayrıntıları şu şekilde görünür:
Native method - android.os.MessageQueue.nativePollOnce
Executing service com.example.app/com.example.app.MyService
Örneğin, ana iş parçacığı boşta ise yığınlar şu şekilde görünür:
"main" tid=1 NativeMain threadIdle
#00 pc 0x00000000000d8b38 /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
#01 pc 0x0000000000019d88 /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
#02 pc 0x0000000000019c68 /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
#03 pc 0x000000000011409c /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce (Native method)
at android.os.MessageQueue.next (MessageQueue.java:339) at android.os.Looper.loop (Looper.java:208)
at android.app.ActivityThread.main (ActivityThread.java:8192)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:626)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1015)
Yanıt vermediği düşünülen iş parçacığının boşta olmasının birkaç nedeni vardır:
"nativePollOnce" ANR'sinin temel tetikleyicileri ANR türüne göre değiştiğinden, belirli ANR kategorisini teşhis etmek, uygulamanızdaki sorunu çözmek için uygulanabilir adımları belirlemenize yardımcı olabilir.
| Kategori | Neden | Önerilen düzeltme |
|---|---|---|
| Giriş gönderme zaman aşımı | Sistem genelinde sorun Geç bellek dökümü |
Herhangi bir işlem yapmanız gerekmez. |
| Odaklanılmış pencere yok | Sistem genelinde sorun Geç yığın dökümü İş parçacığı ihlalini görüntüleme |
Görünüm iş parçacığı ihlalleri için kod tabanını kontrol edin. |
| Yayın alıcı zaman aşımı | Geç yığın dökümü Sistem genelinde sorun Thread'in yanlış ilişkilendirilmesi Thread'in ihlalini görüntüleme |
Yığın dökümündeki ilgili iş parçacıklarını inceleyin. Kod tabanında görünüm iş parçacığı ihlali olup olmadığını kontrol edin. |
| Hizmet yürütme zaman aşımı | Geç yığın dökümü Sistem genelinde sorun İş parçacığı ihlalini görüntüle |
Görünüm iş parçacığı ihlalleri için kod tabanını kontrol edin. |
| İçerik sağlayıcı yanıt vermiyor | Geç yığın dökümü Sistem genelinde sorun İş parçacığı yanlış ilişkilendirmesi |
Yığın dökümündeki ilgili iş parçacıklarını inceleyin. |
NativePollOnce ANR'lerini analiz etmek için önerilen adımlar şunlardır:
Yığın çerçevesi yok
Bazı ANR raporları, ANR'nin bulunduğu yığınları içermez. Bu da ANR raporu oluşturulurken yığın dökümünün başarısız olduğu anlamına gelir. Yığın çerçevelerinin eksik olmasının birkaç olası nedeni vardır:
[...]
--- CriticalEventLog ---
capacity: 20
timestamp_ms: 1666030897753
window_ms: 300000
libdebuggerd_client: failed to read status response from tombstoned: timeout reached?
----- Waiting Channels: pid 7068 at 2022-10-18 02:21:37.<US_SOCIAL_SECURITY_NUMBER>+0800 -----
[...]
Yığın çerçeveleri içermeyen ANR'ler, küme imzası veya ANR raporundan işleme alınamaz. Hata ayıklamak için uygulamanın diğer kümelerine bakın. Sorun yeterince büyükse genellikle yığın çerçevelerinin bulunduğu kendi kümesi olur. Diğer bir seçenek de Perfetto izlerine bakmaktır.
Bilinen sorunlar
ANR tetiklenmeden önce yayın işleme sürecini tamamlamak için uygulamanızın sürecinde bir zamanlayıcı tutmak, sistemin ANR'leri eşzamansız olarak izlemesi nedeniyle doğru şekilde çalışmayabilir.