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 sistemi, kullanıcıya Şekil 1'de gösterildiği gibi bir iletişim kutusu görüntüler. ANR iletişim kutusu kullanıcıya uygulamadan çıkmaya zorlama fırsatı verir.
Şekil 1. Kullanıcıya gösterilen ANR iletişim kutusu
ANR'ler sorun teşkil eder çünkü uygulamanın ana iş parçacığı, Kullanıcı arayüzünün güncellenmesi, kullanıcı girişi etkinliklerinin veya çizim işlemlerinin yapılamaması, temsil eder. Uygulamanın ana iş parçacığı hakkında daha fazla bilgi için İşlemler ve mesaj dizileri.
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 girişlere yanıt vermediyse etkinlik (tuşa basma veya ekrana dokunma gibi) 5 saniye içinde gösterilir.
- Hizmeti yürütme: Uygulamanız tarafından beyan edilen bir hizmet tamamlanamıyorsa
Service.onCreate()
ve Birkaç saniye içindeService.onStartCommand()
/Service.onBind()
. - Service.startForeground() çağrılmadı: Uygulamanız
Ön planda yeni bir hizmet başlatmak için
Context.startForegroundService()
, ancak hizmet 5 saniye içindestartForeground()
öğesini çağırmaz. - Niyet yayını:
BroadcastReceiver
belirli bir süre içinde tamamlanmamıştır. Uygulama, bu zaman aşımı 5 saniyedir. - JobScheduler etkileşimleri:
JobService
dönmüyor birkaç gün içindeJobService.onStartJob()
veyaJobService.onStopJob()
adlı satıcıdan veya kullanıcı tarafından başlatılan iş başlar ve uygulamanız birkaç gün içindeJobService.setNotification()
numaralı telefonu aramazJobService.onStartJob()
çağrıldıktan sonraki saniye. Uygulama hedefleme için Android 13 ve önceki sürümlerde ANR'ler sessizdir ve uygulamaya bildirilmez. Android 14 ve sonraki sürümleri hedefleyen uygulamalar için ANR'ler uygunsuzdur ve bildirilmişti.
Uygulamanızda ANR yaşanıyorsa bu makaledeki bilgilerden yararlanarak ve çözüm bulmak sizin işinizdir.
Sorunu tespit etme
Uygulamanızı daha önce yayınladıysanız Uygulamanızın ANR'leriyle ilgili bilgileri görmek için Android vitals'ı kullanın. Diğer alandaki ANR'leri tespit etmek için kullanabileceğiniz araçlardır, ancak 3. taraf araçlarının Android vitals'ın aksine eski sürümleri (Android 10 ve önceki sürümler) kullanılabilir.
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ılarınız arasında herhangi bir ANR yaşamışsınız.
- Kullanıcı tarafından algılanan ANR oranı: Günlük etkin kullanıcılarınızın yüzdesidir.
kullanıcı tarafından algılanan ANR yaşayan en az bir kullanıcı. Şu anda yalnızca şu ANR'ler:
Input dispatching timed out
türü, kullanıcı tarafından algılanan kabul edilir. - Çoklu ANR oranı: Günlük etkin kullanıcılarınız arasında en az iki ANR yaşadı.
Günlük etkin kullanıcı, uygulamanızı kullanan tekil bir kullanıcıdır (potansiyel olarak birden fazla oturumda) 44 saat boyunca kullanılabilir. Bir kullanıcı aynı gün içinde uygulamanızı birden fazla cihazda kullanırsa her cihaz o gündeki etkin kullanıcı sayısına katkıda bulunur. Birden fazla kullanıcı tek bir gün içinde aynı cihazı kullanırsa bunlar tek bir etkin kullanıcı olarak sayılır.
Kullanıcı tarafından algılanan ANR oranı önemlidir, yani kullanıcı tarafından algılanan ANR oranı uygulamanızın Google Play'deki bulunabilirliği. Bu önemli çünkü ANR'ler, Sayılar her zaman kullanıcı uygulamayla etkileşime geçtiğinde ortaya çıkar. Bu da en çok olabilir.
Play bu metrikte iki kötü davranış eşiği tanımlamıştır:
- Genel kötü davranış eşiği: Günlük etkin kullanıcıların en az% 0,47'si tüm cihaz modellerinde kullanıcı tarafından algılanan ANR sorunu yaşar.
- Cihaz başına kötü davranış eşiği: Günlük kullanıcıların en az% 8'i tek bir cihaz modeli için kullanıcı tarafından algılanan ANR yaşanması gerekir.
Uygulamanız genel kötü davranış eşiğini aşıyorsa büyük olasılıkla tüm cihazlarda daha az bulunabilir. Uygulamanız cihaz başına kötü kullanım oranını aşıyorsa bir davranış eşiğinin üzerine çıktığında, ve mağaza girişinizde bir uyarı gösterilebilir.
Android vitals sizi uyarabilir: Play Console uygulamanız çok fazla ANR veriyorsa.
Google Play'in Android vitals verilerini nasıl topladığı hakkında bilgi için bkz. Play Console belgelerinden faydalanabilirsiniz.
ANR'leri teşhis edin
ANR'leri teşhis ederken bakılması gereken bazı yaygın kalıplar vardır:
- Uygulama, ana iş parçacığında G/Ç ile ilgili 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 eşzamanlı bağlayıcı çağrısı yapıyor ve zaman alıyor.
- Uzun süredir senkronize edilen bir engelleme bekleniyor. Ana iş parçacığı engellendi başka bir iş parçacığında devam eden bir işlem.
- Ana iş parçacığı, ya da bağlayıcı çağrısı yoluyla yapılabilir. Ana iş parçacığı yalnızca uzun bir süre beklemiyor ancak bir kilitlenme durumunda olduğu anlamına gelir. Daha fazla bilgi için Vikipedi'deki Kilitlenme konusuna bakın.
Aşağıdaki teknikler, ANR'lerinizin nedenini belirlemenize yardımcı olabilir.
Sağlık İstatistikleri
HealthStats
, şunlar hakkında metrikler sağlar:
toplam kullanıcı ve sistem süresini, CPU süresini,
ağ, radyo istatistikleri, ekran açma/kapatma zamanı ve uyandırma alarmları. Bu
genel CPU kullanımını ve pil tüketimini ölçmeye yardımcı olur.
Hata ayıkla
Debug
, Android uygulamalarının incelenmesine yardımcı olur
kötü amaçlı yazılımları belirlemek için izleme ve ayırma sayıları dahil olmak üzere geliştirme sırasında
gecikme yaşayabilirsiniz. Çalışma zamanı ve yerel bellek almak için Debug
bileşenini de kullanabilirsiniz
sayaçlar ve bellek ayak izinin tanımlanmasına yardımcı olabilecek bellek metrikleri
belirli bir süreci
gözden geçiriyorum.
Uygulama Çıkış Bilgisi
ApplicationExitInfo
kullanılabilir
içeren bir e-posta alırsınız ve doğrudan
çıkış nedeni olabilir. Buna ANR'ler, düşük bellek, uygulama kilitlenmeleri,
aşırı CPU kullanımı, kullanıcı kesintileri, sistem kesintileri veya çalışma zamanı
izin değişiklikleri.
Yüksek güvenlik modu
StrictMode
sayesinde şunları bulabilirsiniz:
uygulamanızı geliştirirken ana iş parçacığında yanlışlıkla yapılan G/Ç işlemleri.
StrictMode
aracını kullanabilirsiniz
düzeyinde kontrol edebilirsiniz.
Arka plan ANR iletişim kutularını etkinleştir
Android, yayını işlemesi çok uzun süren uygulamalar için ANR iletişim kutuları gösteriyor. Yalnızca cihazın Geliştirici menüsünde Tüm ANR'leri göster seçeneği etkinse mesaj seçenekleri bulabilirsiniz. Bu nedenle, arka plan ANR iletişim kutuları her zaman kullanıcı, ancak uygulama yine de performans sorunları yaşıyor olabilir.
İzleme Görünümü
İzleme sırasında, çalışan uygulamanızın izini görmek için kullanım alanlarını belirleyebilir ve ana iş parçacığının meşgul olduğu yerleri belirleyebilirsiniz. Daha fazla bilgi için hakkında daha fazla bilgi için Traceview ile Profil Oluşturma ve dmtracedump ile aynı.
İz dosyası alma
Android, bir ANR yaşadığında izleme bilgilerini depolar. Daha eski işletim sistemlerinde
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.
ANR izlerine bir cihazdan veya emülatörden şu uygulamayı kullanarak erişebilirsiniz:
Kök olarak Android Debug Bridge (adb):
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
Al hata mesajını kullanarak fiziksel bir cihazdan hata raporu alabilirsiniz. rapor geliştirici seçeneğini veya bir geliştirme makinesidir. Daha fazla bilgi için bkz. Hata yakalama ve okuma raporları inceleyin.
Sorunları düzeltme
Sorunu tanımladıktan sonra, hedeflerinizi iyileştirmek için bu bölümdeki ipuçlarını kullanabilirsiniz. yaygın şekilde görülen sorunları düzeltin.
Ana iş parçacığında yavaş kod
Uygulamanızın ana iş parçacığının daha fazla etkinlik için meşgul olduğu yerleri kodunuzda belirleyin 5 saniyeden fazladır. Uygulamanızdaki şüpheli kullanım alanlarını bulup yeniden üretebilirsiniz.
Örneğin, Şekil 2'de ana iş parçacığının meşgul olduğu bir İzleme Görünümü zaman çizelgesi gösterilmektedir 5 saniyeden fazla sürebiliyor.
Şekil 2. Meşgul bir ana iş parçacığını gösteren izleme görünümü zaman çizelgesi
Şekil 2'de, sorun teşkil eden kodun çoğu
onClick(View)
işleyicisi şu kod örneğinde gösterildiği gibidir:
Kotlin
override fun onClick(v: View) { // This task runs on the main thread. BubbleSort.sort(data) }
Java
@Override public void onClick(View view) { // This task runs on the main thread. BubbleSort.sort(data); }
Bu durumda, ana iş parçacığında çalışan işi bir çalışana taşımanız gerekir ileti dizisi. Android Framework, görevi taşımanıza yardımcı olabilecek sınıflar içerir iş parçacığına gönderir. Bkz. Çalışan Daha fazlası için: ekleyebilirsiniz.
Ana iş parçacığında KS
Ana iş parçacığında IO işlemleri yürütmek, yavaş işlemlerin yaygın bir nedenidir bu da ANR'lere neden olabilir. Tüm KS'leri taşımanız önerilir işlemlerini bir çalışan iş parçacığına bağlayabilirsiniz.
G/Ç işlemlerine örnek olarak ağ ve depolama işlemleri verilebilir. Daha fazla Daha fazla bilgi için Ağ gerçekleştirme işlemler ve Kaydetme verileri ile karşılaştırın.
Kilit anlaşmazlığı
Bazı senaryolarda, ANR'ye neden olan işler ana iş parçacığı. Bir çalışan iş parçacığı bir kaynakta kilit tutarken ana iş parçacığının çalışmasını tamamlaması gerekiyorsa ANR olabilir.
Örneğin, Şekil 3’te işin çoğunun olduğu bir İzleme Görünümü zaman çizelgesi gösterilmektedir gerçekleştirildiğini gösterir.
Şekil 3. Bir çalışan üzerinde yürütülmekte olan çalışmayı gösteren Traceview zaman çizelgesi iş parçacığı
Ancak kullanıcılarınız hâlâ ANR sorunu yaşıyorsa
Android Device Monitor'daki ana iş parçacığınız. Ana iş parçacığı genellikle
RUNNABLE
hazır olduğunu ve genel olarak duyarlı olduğunu belirtir.
Ancak ana ileti dizisi yürütmeyi devam ettiremiyorsa
BLOCKED
eyalet
ve etkinliklere yanıt veremez. Durum, Android Cihaz Monitörü'nde şu şekilde gösterilir:
Şekil 5'te gösterildiği gibi İzle veya Bekle'yi tıklayın.
4.Şekil İzleme durumundaki ana iş parçacığı
Aşağıdaki izde, uygulamanın bir yüklemenin tamamlanması beklenirken engellenen bir ana iş parçacığı gösteriliyor. kaynak:
...
AsyncTask #2" prio=5 tid=18 Runnable
| group="main" sCount=0 dsCount=0 obj=0x12c333a0 self=0x94c87100
| sysTid=25287 nice=10 cgrp=default sched=0/0 handle=0x94b80920
| state=R schedstat=( 0 0 0 ) utm=757 stm=0 core=3 HZ=100
| stack=0x94a7e000-0x94a80000 stackSize=1038KB
| held mutexes= "mutator lock"(shared held)
at com.android.developer.anrsample.BubbleSort.sort(BubbleSort.java:8)
at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:147)
- locked <0x083105ee> (a java.lang.Boolean)
at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:135)
at android.os.AsyncTask$2.call(AsyncTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
...
İzi incelemek, ana iş parçacığını engelleyen kodu bulmanıza yardımcı olabilir. Aşağıdaki kod, ana makineyi engelleyen kilidin tutulmasından önceki izdeki iş parçacığı:
Kotlin
override fun onClick(v: View) { // The worker thread holds a lock on lockedResource LockTask().execute(data) synchronized(lockedResource) { // The main thread requires lockedResource here // but it has to wait until LockTask finishes using it. } } class LockTask : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? = synchronized(lockedResource) { // This is a long-running operation, which makes // the lock last for a long time BubbleSort.sort(params[0]) } }
Java
@Override public void onClick(View v) { // The worker thread holds a lock on lockedResource new LockTask().execute(data); synchronized (lockedResource) { // The main thread requires lockedResource here // but it has to wait until LockTask finishes using it. } } public class LockTask extends AsyncTask<Integer[], Integer, Long> { @Override protected Long doInBackground(Integer[]... params) { synchronized (lockedResource) { // This is a long-running operation, which makes // the lock last for a long time BubbleSort.sort(params[0]); } } }
Başka bir örnek de bir uygulamanın
aşağıdaki kodda gösterildiği gibi çalışan iş parçacığının bir kısmını içerir. wait()
ve
notify()
, kendi mekanizmaları olan Kotlin'de önerilen bir kalıp değildir
benzersiz bir araçtır. Kotlin kullanırken Kotlin'e özel kullanmanız gerekir.
mekanizmalardan yararlanmayı öğreteceğim.
Kotlin
fun onClick(v: View) { val lock = java.lang.Object() val waitTask = WaitTask(lock) synchronized(lock) { try { waitTask.execute(data) // Wait for this worker thread’s notification lock.wait() } catch (e: InterruptedException) { } } } internal class WaitTask(private val lock: java.lang.Object) : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? { synchronized(lock) { BubbleSort.sort(params[0]) // Finished, notify the main thread lock.notify() } } }
Java
public void onClick(View v) { WaitTask waitTask = new WaitTask(); synchronized (waitTask) { try { waitTask.execute(data); // Wait for this worker thread’s notification waitTask.wait(); } catch (InterruptedException e) {} } } class WaitTask extends AsyncTask<Integer[], Integer, Long> { @Override protected Long doInBackground(Integer[]... params) { synchronized (this) { BubbleSort.sort(params[0]); // Finished, notify the main thread notify(); } } }
Ana ileti dizisini engelleyebilecek bazı durumlar da vardır:
Lock
kullanan ileti dizileri,
Semaphore
,
yanı sıra bir kaynak havuzu (veri tabanı bağlantıları havuzu gibi)
mekanizmaları devre dışı bırakılır.
Genel olarak uygulamanızın kaynakları üzerindeki kilitlerini değerlendirmelisiniz ancak ANR'leri önlemek istiyorsanız kaynaklar ve diğer yollar için ana iş parçacığı tarafından gerekli kılınır.
Kilitlerin en az süre veya daha da iyi bir süre boyunca tutulduğundan emin olun.
her şeyden önce uygulamanın muhafazaya ihtiyacı olup olmadığını değerlendirebilir.
bir çalışan iş parçacığının işlenmesine göre kullanıcı arayüzünün ne zaman güncelleneceğini belirlemek için kilit
müzakere becerilerinizi gösteren
onProgressUpdate()
ve
onPostExecute()
iş parçacığı ile ana iş parçacığı arasında
iletişim kurmak için kullanılır.
Kilitlenmeler
Bir iş parçacığı zorunlu bir ayar nedeniyle bekleme durumuna girdiğinde kaynağı başka bir iş parçacığı tarafından tutuluyor. Bu iş parçacığı da ele alacağız. Uygulamanın ana iş parçacığı bu durumdaysa ANR'ler büyük olasılıkla inceleyebilirsiniz.
Kilitlenmeler, bilgisayar biliminde iyi araştırılmış bir olgudur ve kilitlenmeleri önlemek için kullanabileceğiniz kilitlenme önleme algoritmalarıdır.
Daha fazla bilgi için Kilitlenme ve Kilitlenmeyi önleme algoritmaları açık Vikipedi.
Yavaş yayın alıcıları
Uygulamalar, uçağı etkinleştirme veya devre dışı bırakma gibi anonslara yanıt verebilir yayın alıcıları aracılığıyla bağlantı durumunda yapılan bir değişikliği ifade eder. ANR uygulamanın yayın mesajını işlemesi çok uzun sürdüğünde gerçekleşir.
ANR aşağıdaki durumlarda gerçekleşir:
- Yayın alıcı, henüz çalışmasını tamamlamadı
onReceive()
bir yöntem kullanmayı tercih edebilir. - Yayın alıcı çağrıyı
goAsync()
ve çağrı yapılamaz.finish()
uygulamasındaPendingResult
nesnesini tanımlayın.
Uygulamanız
onReceive()
a
BroadcastReceiver
.
Ancak, uygulamanız daha karmaşıksa
belli bir yayın mesajının sonucu olarak işlendiğinde, bu görevi
IntentService
.
Yayın alıcınızın yayın yapıp yapmadığını belirlemek için Traceview gibi araçlar kullanabilirsiniz uygulamanın ana iş parçacığında uzun süreli işlemler gerçekleştirme. Örneğin, Şekil 6'da ana iş parçacığındaki bir mesajı işleyen yayın alıcısının zaman çizelgesi yaklaşık 100 saniyeliğine ayarlanır.
5. Şekil. Şuradaki BroadcastReceiver
çalışmasını gösteren Traceview zaman çizelgesi:
ana iş parçacığı
Bu davranış,
onReceive()
yöntemindeki
BroadcastReceiver
,
aşağıdaki örnekte gösterildiği gibi:
Kotlin
override fun onReceive(context: Context, intent: Intent) { // This is a long-running operation BubbleSort.sort(data) }
Java
@Override public void onReceive(Context context, Intent intent) { // This is a long-running operation BubbleSort.sort(data); }
Bu gibi durumlarda uzun süren işlemi
IntentService
bir çalışan iş parçacığı kullanır. Aşağıdaki kod,
Bir öğeyi işlemek için IntentService
uzun süreli işlem:
Kotlin
override fun onReceive(context: Context, intent: Intent) { Intent(context, MyIntentService::class.java).also { intentService -> // The task now runs on a worker thread. context.startService(intentService) } } class MyIntentService : IntentService("MyIntentService") { override fun onHandleIntent(intent: Intent?) { BubbleSort.sort(data) } }
Java
@Override public void onReceive(Context context, Intent intent) { // The task now runs on a worker thread. Intent intentService = new Intent(context, MyIntentService.class); context.startService(intentService); } public class MyIntentService extends IntentService { @Override protected void onHandleIntent(@Nullable Intent intent) { BubbleSort.sort(data); } }
IntentService
,
işlem ana iş parçacığı yerine bir çalışan iş parçacığı üzerinde yürütülür. 7. Şekil
, Traceview zaman çizelgesinde çalışan iş parçacığına ertelenen çalışmayı gösterir.
6. Şekil. çalışan iş parçacığı
Yayın alıcınız
goAsync()
mesajı işlemesi için daha fazla zamana ihtiyaç duyduğunu belirten bir işaret oluşturabilirsiniz. Ancak,
telefon etmeli
finish()
uygulamasında
PendingResult
nesnesini tanımlayın. Aşağıdaki örnekte, sistemin
yayın alıcısını geri dönüştürün ve ANR'yi önleyin:
Kotlin
val pendingResult = goAsync() object : AsyncTask<Array<Int>, Int, Long>() { override fun doInBackground(vararg params: Array<Int>): Long? { // This is a long-running operation BubbleSort.sort(params[0]) pendingResult.finish() return 0L } }.execute(data)
Java
final PendingResult pendingResult = goAsync(); new AsyncTask<Integer[], Integer, Long>() { @Override protected Long doInBackground(Integer[]... params) { // This is a long-running operation BubbleSort.sort(params[0]); pendingResult.finish(); } }.execute(data);
Ancak, kodu yavaş bir yayın alıcısından başka bir iş parçacığına taşımak ve
goAsync()
kullanılıyor
yayın arka plandaysa ANR sorunu çözülmez.
ANR zaman aşımı geçerli olmaya devam eder.
Oyun Etkinliği
GameActivity
kitaplığının ANR sayısını azalttığı ülke:
oyunlar ve uygulamalarla ilgili örnek olaylar
C veya C++ yazın. Mevcut yerel etkinliğinizi GameActivity
ile değiştirirseniz
kullanıcı arayüzü iş parçacığı engellemesini azaltabilir ve bazı ANR'lerin meydana gelmesini önleyebilirsiniz.
ANR'ler hakkında daha fazla bilgi için bkz. Uygulamanızın duyarlı kalmasını sağlama. Daha fazla ileti dizileri hakkında bilgi için bkz. Mesaj dizisi performansı.
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Aşırı sayıda uyandırma