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 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

Ş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ı, gösterir. 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çinde Service.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çinde startForeground() öğ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çinde JobService.onStartJob() veya JobService.onStopJob() adlı satıcıdan veya kullanıcı tarafından başlatılan iş başlar ve uygulamanız birkaç gün içinde JobService.setNotification() numaralı telefonu aramaz JobService.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. Yoğun bir ana makineyi gösteren izleme zaman çizelgesi
iş parçacığı

Ş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ığı

Ş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.

Şekil 4. Monitör&#39;deki ana iş parçacığı
durum

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ında PendingResult 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.

Şekil 5. Ana ekranda &quot;BroadcastReceiver&quot; çalışmasını gösteren izleme görünümü zaman çizelgesi
iş parçacığı

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.

Şekil 6. 
çalışan iş parçacığı

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ı.

ziyaret edin.