Android uygulamalarında ANR kaynağını Android Vitals, StrictMode ve Perfetto ile yeniden üretin; ana thread blokajını ölçün, Kotlin coroutine sınırlarını düzeltin ve sürüm sonrası regresyonu izleyin.
Android Eğitimi: ANR'leri Perfetto ve StrictMode ile Kökten İncelemek
Android eğitimi kapsamında ANR sinyalini doğru sınıflandırmak
ANR incelemesine yalnızca stack trace okuyarak başlamayın. Play Console Android Vitals ekranındaki kullanıcı etkilenme oranını, etkilenen cihaz modellerini ve Android sürümü dağılımını aynı sürüm kodu için filtreleyin. Ardından uygulama içinde ApplicationExitInfo kayıtlarını toplayın. Bu kayıt, özellikle süreç öldükten sonra üretimde görülen REASON_ANR olaylarını crash analitiğiyle eşleştirmenizi sağlar. Bir android eğitim veya android kursu içeriğinde kritik ayrım şudur: girişteki ANR ile broadcast receiver ANR'si aynı semptomu üretse de timeout'u bekleyen sistem bileşeni farklıdır.
fun reportRecentAnrs(context: Context) {
val am = context.getSystemService(ActivityManager::class.java)
val exits = am.getHistoricalProcessExitReasons(
context.packageName,
0,
20
)
exits.filter { it.reason == ApplicationExitInfo.REASON_ANR }
.forEach { info ->
Log.e(
"AnrReport",
"timestamp=${info.timestamp}, importance=${info.importance}, " +
"description=${info.description}"
)
}
}Bu API yalnızca desteklenen platform seviyelerinde ve sistemin tuttuğu sınırlı geçmiş kadar veri döndürür; her ANR'nin tam Java trace'ini uygulamaya vermez. Bu nedenle kaydı cihaz modeli, uygulama sürüm kodu, son ekran rotası ve devam eden iş kimliğiyle ilişkilendirin. Analitiğe ham kullanıcı girdisi veya URL query parametresi göndermeyin. Yerelde doğrulama için test cihazında adb shell dumpsys activity exit-info your.package.name komutunu çalıştırın; logcat'teki zaman damgası ile ApplicationExitInfo.timestamp değerinin uyuştuğunu kontrol edin.
Kotlin eğitimi için ana thread I/O'sunu StrictMode ile yakalamak
ANR'lerin sık nedeni, ana thread üzerinde disk erişimi, senkron veritabanı sorgusu, bitmap decode veya yanlış dispatcher kullanımıdır. StrictMode bu işlemleri kendi başına hızlandırmaz; ihlalin gerçekleştiği çağrı anında stack trace üretir. Mekanizma önemlidir: Looper mesaj kuyruğunu işleyen ana thread, bloklayan çağrı dönene kadar input dispatch, lifecycle ve çizim mesajlarını işleyemez. Debug ve internal dağıtımlarda aşağıdaki politikayı Application.onCreate() içinde etkinleştirin.
class App : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.detectCustomSlowCalls()
.penaltyLog()
.penaltyFlashScreen()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectLeakedClosableObjects()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.build()
)
}
}
}Kotlin kursu örneklerinde sık görülen hata, suspend fonksiyonun otomatik olarak arka planda çalıştığını varsaymaktır. suspend yalnızca çağrının askıya alınabilir olduğunu belirtir; fonksiyon çağrıldığı coroutine context'te başlar. Örneğin JSON parse işlemi ViewModel'in ana dispatcher'ında başladıysa büyük payload ana thread'i meşgul eder. Ağ isteği zaten OkHttp'nin kendi thread'lerinde ilerlese bile, response mapping kısmı için dispatcher sınırını açık koyun: val dto = withContext(dispatchers.default) { json.decodeFromString<Dto>(body) }. Room'un suspend DAO'ları sorguyu uygun executor'a alabilir, ancak DAO sonucundan sonra yaptığınız sıralama, map veya kriptografik dönüşüm için aynı garanti yoktur.
Perfetto ile ANR öncesi scheduler ve Binder gecikmesini ölçmek
Bir android studio eğitimi laboratuvarında profiler grafiği yararlıdır, fakat sistem servisleriyle olan beklemeyi görmek için Perfetto trace daha kesin kanıt sağlar. Önce cihazın desteklediği event adlarını doğrulayın: adb shell perfetto --query-raw | grep -E 'sched_switch|binder_transaction'. Sonra sorunu yeniden üretirken scheduler, Binder ve block I/O event'lerini kaydedin. Event isimleri çekirdek yapılandırmasına göre değişebileceğinden sorgu sonucu yoksa trace config'ten o event'i çıkarın.
adb shell perfetto --txt -c - -o /data/misc/perfetto-traces/anr.pftrace <<'EOF'
buffers: { size_kb: 32768 fill_policy: RING_BUFFER }
data_sources: {
config {
name: "linux.ftrace"
ftrace_config {
ftrace_events: "sched/sched_switch"
ftrace_events: "sched/sched_waking"
ftrace_events: "binder/binder_transaction"
ftrace_events: "binder/binder_transaction_received"
ftrace_events: "block/block_rq_issue"
ftrace_events: "block/block_rq_complete"
atrace_categories: "am"
atrace_categories: "wm"
atrace_categories: "view"
atrace_categories: "gfx"
}
}
}
duration_ms: 20000
EOF
adb pull /data/misc/perfetto-traces/anr.pftraceTrace'i ui.perfetto.dev üzerinde açıp ana thread'in Running, Runnable ve Sleeping aralıklarını ayırın. Uzun Running dilimi CPU'da çalışan parse veya layout işine, uzun Sleeping dilimi çoğunlukla kilit, Binder yanıtı ya da I/O beklemesine işaret eder. Uzun Runnable ise iş hazır olduğu halde CPU zaman dilimi alamadığını gösterir; bunu uygulama kodunu optimize ederek çözemezsiniz, cihazdaki CPU contention veya yanlış önceliklendirme araştırılır.
Önce-sonra karşılaştırmasını aynı cihaz, aynı uygulama sürüm yapılandırması ve aynı test senaryosunda yapın. Örneğin ana thread'de 12 MB JSON decode edilen trace'te input event ile ilk çizim arasındaki süreyi ve ana thread'in en uzun kesintisiz çalışma dilimini kaydedin. Ardından decode'u Dispatchers.Default context'ine taşıyın, tekrar trace alın ve aynı iki metriği karşılaştırın. Sadece toplam trace süresine bakmak yanıltıcıdır: arka plan işine taşıma CPU kullanımını artırabilir, fakat ANR açısından önemli sonuç ana Looper'ın tekrar mesaj işleyebilmesidir.
Jetpack Compose ve Android MVVM mimarisi içinde blokaj sınırları
Jetpack Compose kullanan uygulamalarda pahalı işin composable gövdesine girmesi, her yeniden çizimde ana thread maliyetini yeniden üretir. Android MVVM mimarisi içinde ViewModel, UI için önceden hazırlanmış immutable state yayınlamalı; composable yalnızca state'i tüketmelidir. runBlocking'i click handler, repository veya composable içinde kullanmayın: çağıran thread'i coroutine tamamlanana kadar bloke eder ve ana thread'de çalışıyorsa input dispatch'i durdurur.
class ProductViewModel(
private val repository: ProductRepository,
private val dispatchers: AppDispatchers
) : ViewModel() {
private val _uiState = MutableStateFlow(ProductUiState())
val uiState: StateFlow<ProductUiState> = _uiState.asStateFlow()
fun refresh() = viewModelScope.launch {
_uiState.update { it.copy(loading = true) }
val products = withContext(dispatchers.default) {
repository.fetchProducts()
.sortedBy { it.displayName.lowercase(Locale.ROOT) }
.map { it.toUiModel() }
}
_uiState.update { ProductUiState(items = products, loading = false) }
}
}Burada dispatcher injection test edilebilirlik için de gereklidir: unit testte StandardTestDispatcher vererek coroutine tamamlanma sırasını denetleyebilirsiniz. Ancak tüm repository çağrılarını körlemesine Dispatchers.Default'a koymayın. Ağ ve dosya I/O için sınırlı paralelliğe sahip bir Dispatchers.IO türevi, CPU ağırlıklı sıralama ve serialization için ise Default daha uygundur. Aksi halde yoğun disk işini CPU havuzuna taşıyıp ana thread ANR'sini çözseniz bile ekranın ihtiyaç duyduğu CPU zamanını dolaylı olarak azaltabilirsiniz.
Mobil uygulama geliştirme eğitimi için sürüm kapısı ve Play Store yayınlama
Mobil uygulama geliştirme eğitimi süreçlerinde ANR düzeltmesini 'lokalde hissedildi' notuyla kapatmayın. CI üzerinde Macrobenchmark ile tam ANR simülasyonu üretmek her zaman gerçekçi değildir, ancak kritik akışların frame ve süre regresyonunu sayısallaştırabilirsiniz. Örneğin giriş sonrası büyük katalog açılışında FrameTimingMetric() ve TraceSectionMetric("catalog_mapping") kaydedin; mapping kodunu Trace.beginSection("catalog_mapping") ve Trace.endSection() ile çevreleyin. Benchmark sonucu önceki ana dala göre p95 frame süresi veya trace bölümü süresinde belirlediğiniz eşik kadar artarsa merge'i durdurun.
Play Store yayınlama sonrasında staged rollout kullanın ve Android Vitals'ta yeni sürüm kodunun ANR oranını önceki kararlı sürümle karşılaştırın. Karşılaştırmayı tüm kullanıcılar yerine aynı ülke, cihaz RAM sınıfı ve uygulama sürümü segmentlerinde yapın; aksi halde yeni cihaz dağılımı yanlış bir iyileşme veya bozulma görüntüsü verebilir. Android Vitals'ta artış görürseniz, sürüm kodunu ApplicationExitInfo olayları ve Perfetto'da bulduğunuz bekleme imzasıyla eşleştirin. Bu kapanış döngüsü, bir kotlin eğitimi projesindeki dispatcher değişikliğinin üretimde gerçekten hangi kullanıcı grubunu etkilediğini gösterir.
İlgili Eğitim
YTÜSEM İlgili Eğitim
Sık Sorulan Sorular
Android eğitimi sırasında ANR ile crash arasındaki farkı nasıl üretimde ayırırım?
Crash için crash reporting SDK'nızdaki exception ve fatal event'leri, ANR için Play Console Android Vitals ile ActivityManager.getHistoricalProcessExitReasons() içindeki REASON_ANR kayıtlarını ayrı sorgulayın. Aynı sürüm kodu ve cihaz modeli üzerinde timestamp korelasyonu yapın; ANR kaydı her zaman uygulamanın yakalayabileceği bir exception içermez.
Kotlin eğitimi örneğinde suspend fonksiyon neden ana thread ANR'sine yol açabilir?
Suspend fonksiyon çağrıldığı coroutine context'te çalışmaya başlar. viewModelScope varsayılan olarak Main dispatcher kullandığından, büyük JSON parse, sıralama veya şifre çözme işlemini withContext(dispatchers.default) olmadan yapmak ana Looper'ı meşgul eder. StrictMode disk ve network ihlallerini yakalar, CPU ağırlıklı işi ise Perfetto'da ana thread Running dilimi olarak doğrularsınız.
Jetpack Compose uygulamasında ANR incelemek için Android Studio yeterli mi?
Android Studio CPU Profiler kısa yerel örneklerde yararlıdır; Binder çağrıları, scheduler gecikmesi ve block I/O için Perfetto ekleyin. perfetto --query-raw ile cihaz event'lerini doğrulayın, aynı kullanıcı akışında önce-sonra trace alın ve ana thread'in en uzun Running, Runnable ve Sleeping aralıklarını ayrı metrikler olarak kıyaslayın.
Android kursu projesinde Play Store yayınlama öncesi hangi ANR kontrolünü otomatikleştirmeliyim?
Kritik ekranlar için Macrobenchmark FrameTimingMetric ve uygulamaya eklenmiş TraceSectionMetric çalıştırın. CI'da p95 frame süresi ve katalog mapping trace süresini önceki kararlı baseline ile karşılaştırın. Yayın sonrası staged rollout segmentinde Android Vitals ANR oranını cihaz RAM sınıfı ve sürüm koduna göre inceleyin.
AI / LLM Discovery
Bu makale Opendart Akademi Android eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.



