ANR(Application Not Responding)은 앱이 5초 이상 사용자 입력에 응답하지 않을 때 나타나는 Android 시스템 알림입니다. Android Developers에 따르면, 주요 원인은 메인 스레드에서의 긴 작업으로 인해 터치 처리와 UI 렌더링이 차단되는 것입니다. 응답성이 뛰어난 애플리케이션을 만들기 위해 모든 Android 개발자는 ANR 메커니즘을 이해하는 것이 필수적입니다.
핵심 요점
ANR(Application Not Responding)은 앱이 사용자 입력에 응답하지 않을 때 나타나는 Android 운영 체제의 대화 상자입니다. 시스템은 InputDispatcher를 통해 이벤트 처리 시간을 추적합니다. 터치 또는 버튼 누름이 5초 이내에 처리되지 않으면 Android는 앱을 닫거나 기다리라는 대화 상자를 표시합니다.
ANR 메커니즘은 멈춘 앱으로부터 사용자 경험을 보호합니다. Android는 하나의 앱이 전체 시스템을 차단하는 것을 허용하지 않습니다. 데스크톱 OS와 달리 모바일 플랫폼은 이벤트 처리 시간을 강제로 제한합니다. BroadcastReceiver는 10초 제한이 있고 포그라운드 서비스는 20초 제한이 있습니다.
ANR은 코드의 예외가 아닙니다. Linux 프로세스 수준의 시스템 메커니즘입니다. Android는 프로세스에 SIGQUIT 신호를 보내고, 시스템은 모든 스레드의 호출 스택을 traces.txt 파일에 저장합니다. 개발자는 ANR을 catch 예외가 아니라 앱 재시작 후 보고서로 받습니다. Android 11 이상에서는 ApplicationExitInfo API를 사용하여 ANR을 포함한 프로세스 종료 이유를 프로그래밍 방식으로 얻을 수 있습니다. 이렇게 하면 수동 traces.txt 파싱 없이 통계 수집이 간소화됩니다.
다섯 가지 범주의 작업이 Android 앱에서 지속적으로 ANR을 유발합니다. 각각은 메인 스레드를 차단하여 시스템이 입력 이벤트와 화면 다시 그리기를 처리하지 못하게 합니다.
UI 스레드에서 실행되는 동기 HTTP 요청은 초보 개발자에게 ANR의 가장 흔한 원인입니다. 서버에 대한 빠른 요청도 1~3초가 걸릴 수 있으며, 연결이 좋지 않으면 30초 이상 걸릴 수 있습니다. Android는 API 11부터 메인 스레드에서 네트워크 작업을 명시적으로 금지하고 NetworkOnMainThreadException을 발생시킵니다.
비동기 호출에는 Coroutines 또는 RxJava를 사용하세요. Dispatchers.IO 디스패처가 있는 코루틴은 백그라운드 스레드에서 요청을 실행하고 Dispatchers.Main을 통해 결과를 메인 스레드에 전달합니다. 이렇게 하면 네트워크 작업으로 인한 UI 스레드 차단이 완전히 제거됩니다.
fun fetchUserData() {
CoroutineScope(Dispatchers.Main).launch {
val result = withContext(Dispatchers.IO) {
api.getUserData() // 백그라운드 작업
}
updateUI(result) // 메인 스레드에서의 결과
}
}
큰 데이터 배열 처리, JSON 또는 XML 파싱, 메인 스레드에서 비트맵 직접 작업은 ANR의 두 번째로 흔한 원인입니다. 이벤트 루프로 돌아가지 않고 UI 스레드가 300밀리초 연속으로 작업해도 렌더링에 눈에 띄는 지연이 발생하며, 5초 임계값에 도달하면 ANR로 기록됩니다.
WorkManager와 백그라운드 서비스는 메인 스레드에서 무거운 계산을 옮기기 위해 설계되었습니다. UI를 차단하지 않고 데이터를 청크로 전달하려면 AsyncTask(더 이상 사용되지 않음), ListenableFuture 또는 Kotlin Flow를 사용하세요.
Deadlock은 두 스레드가 잠금을 보유하고 서로를 기다릴 때 발생합니다. 스레드 중 하나가 메인 스레드인 경우 시스템은 정확히 5초 후에 ANR을 기록합니다. UI 스레드에서 호출되는 Thread.join(), CountDownLatch.await() 및 synchronized 블록은 차단 위험이 있습니다.
메인 스레드에서 차단 작업을 피하세요. synchronized 대신 ConcurrentHashMap을, Thread.join() 대신 async/await가 있는 코루틴을 사용하세요. 이 규칙은 Android의 모든 언어(Java, Kotlin, JNI를 통한 C++)에 적용됩니다.
BroadcastReceiver는 기본적으로 메인 스레드에서 실행됩니다. onReceive()가 10초 이상 바쁘면 Android가 ANR을 표시합니다. onReceive 내에서 데이터베이스나 네트워크에서 데이터를 로드하는 것은 멈춤으로 가는 확실한 경로입니다.
백그라운드 스레드로 전환하려면 BroadcastReceiver 내에서 goAsync()를 사용하거나 getBackgroundBroadcastReceiver()로 registerReceiver를 사용하세요. 이렇게 하면 UI를 차단하지 않고 이벤트를 처리할 수 있습니다.
ContentProvider에 대한 무거운 쿼리 또는 UI 스레드에서 SQLite 직접 작업은 덜 명확하지만 흔한 ANR 원인입니다. 데이터베이스 마이그레이션이나 수천 개의 레코드 대량 삽입 중에 실행 시간이 5초 제한을 초과할 수 있습니다.
모든 데이터베이스 작업은 suspend 함수와 함께 Room을 통해 백그라운드 스레드로 이동하세요. Room은 쿼리가 메인 스레드에서 실행되지 않는지 자동으로 확인하고 위반 시 예외를 발생시킵니다.
ANR 진단은 일반 예외 디버깅과 다릅니다. try-catch 블록에서 ANR을 잡을 수 없습니다. 주요 정보 출처는 Android가 멈춤 시점에 생성하는 traces.txt 파일입니다.
traces.txt에는 ANR 시점의 모든 앱 스레드 호출 스택이 포함됩니다. 실제 기기에서 파일을 읽으려면 adb bugreport 명령을 실행하여 최근 모든 ANR을 포함한 전체 시스템 보고서를 수집하세요. 에뮬레이터의 경우 파일은 /data/anr/traces.txt에서 확인할 수 있습니다. 호출 스택은 차단 시점에 메인 스레드에서 실행 중이던 메서드를 보여줍니다.
adb bugreport bugreport.zip
unzip -p bugreport.zip "*traces*" > traces.txt
Google Play Console은 집계된 보고서와 오류 빈도가 포함된 ANR & Crash 섹션을 제공합니다. 각 ANR에 대해 호출 스택과 기기 통계(모델, Android 버전, 지역)가 표시됩니다. 이를 통해 특정 기기나 시스템 버전에 의존하는 ANR을 식별할 수 있습니다.
Android Studio는 2021년부터 프로파일러에 ANR Watchdog을 포함했습니다. 메인 스레드가 임계 시간보다 오래 응답하지 않으면 자동으로 스레드 덤프를 기록합니다. 이 도구는 이벤트 타임라인을 보여줍니다. 어떤 작업이 시작되었고, 어떤 메서드가 실행되었으며, 어떤 단계에서 차단이 발생했는지 확인할 수 있습니다.
ANR 예방은 하나의 기본 규칙에 기반합니다. 메인 스레드는 UI 이벤트만 처리해야 합니다. 16밀리초(한 프레임 시간)보다 긴 작업은 백그라운드 스레드에서 실행해야 합니다.
StrictMode는 개발 중 잠재적 ANR을 감지하는 Android 내장 도구입니다. 디스크 및 네트워크 작업에 대한 플래그와 함께 Application.onCreate()에서 활성화하세요. 위반 시 StrictMode는 예외를 발생시키거나 logcat에 기록합니다.
if (BuildConfig.DEBUG) {
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
.let { StrictMode.setThreadPolicy(it) }
}
Kotlin Coroutines은 최신 Android 앱에서 비동기 작업의 표준 방식입니다. 핵심 접근법: I/O 작업은 Dispatchers.IO에서 실행되고, 결과는 UI 업데이트를 위해 Dispatchers.Main으로 전달됩니다. Flow와 같은 시나리오의 경우 CPU 집약적 작업에 Dispatchers.Default를 사용하세요.
RxJava는 레거시 프로젝트에서 여전히 인기가 있습니다. subscribeOn(Schedulers.io())와 observeOn(AndroidSchedulers.mainThread())은 ANR을 방지하기 위한 최소 설정입니다. 주요 규칙은 동일합니다. Observable이나 Flowable은 메인 스레드에서 데이터를 방출해서는 안 됩니다.
Firebase Crashlytics는 SDK 버전 18.4.0부터 ANR 모니터링을 기본적으로 지원합니다. Android 11 이상의 경우 Crashlytics는 시스템 API ApplicationExitInfo를 사용하여 정확한 종료 이유(ANR, Crash 또는 시스템 종료)를 제공합니다. 컨텍스트 분석을 위해 화면 및 상태 매개변수가 있는 커스텀 키를 활성화하세요.
5가지 도구가 ANR 작업의 모든 단계(워크스테이션에서 디버깅부터 프로덕션 모니터링까지)를 포괄합니다. 각 도구는 자체 작업을 해결하고 다양한 시나리오에 데이터를 제공합니다.
| 도구 | 목적 | 데이터 형식 |
|---|---|---|
| StrictMode | 개발 중 감지 | Logcat / Exception |
| ANR Watchdog(Android Studio) | 실시간 추적 | Thread dump + timeline |
| Google Play Console | 집계 통계 | ANR rate + stack traces |
| Firebase Crashlytics | 프로덕션 모니터링 | ApplicationExitInfo |
| adb bugreport | 전체 시스템 보고서 | traces.txt + logcat + dmesg |
각 도구에는 자체 영역이 있습니다. StrictMode는 초기 단계에서 명백한 위반을 잡아내고, Crashlytics는 사용자 간 실제 ANR 빈도를 보여주며, adb bugreport는 복잡한 경우에 가장 완전한 그림을 제공합니다. 완전한 커버리지를 위해 이들을 결합하세요.
Firebase Performance는 UI 스레드 응답 시간을 추적하고 의심스럽게 긴 작업에 대해 자동으로 트레이스를 생성합니다. 메인 스레드가 500ms 이상 차단되면 Performance는 원인이 된 메서드 이름으로 커스텀 트레이스를 기록합니다. 이를 통해 사용자 개입 없이 심각해지기 전에 ANR 시나리오를 감지할 수 있습니다.
Firebase Crashlytics와의 통합은 완전한 그림을 제공합니다. Performance는 ANR 전의 느려짐을 보여주고 Crashlytics는 멈춤 자체를 보여줍니다. Firebase Console에서 ANR 비율이 0.1%를 초과할 때 알림을 설정하면 사용자의 대량 불만 이전에 새 문제에 대한 알림을 받을 수 있습니다.
자주 묻는 질문
ANR은 앱이 응답하지 않지만 메모리에 남아 있는 멈춤입니다. Crash는 프로세스 종료를 동반한 완전한 비정상 종료입니다. ANR은 시스템이나 사용자가 응답을 기다리면 “살아남을” 수 있지만 Crash는 항상 앱을 종료합니다.
아니요. ANR은 Java/Kotlin 예외가 아니라 프로세스 수준의 시스템 신호(SIGQUIT)입니다. 개발자는 애플리케이션 코드에서 이를 처리할 수 없습니다. ANR에 대응하는 유일한 방법은 재시작 후 보고서를 분석하는 것입니다.
기기 성능, Android 버전, CPU 부하 및 백그라운드 프로세스 수가 ANR 가능성에 영향을 미칩니다. 성능이 낮은 기기에서는 동일한 작업이 2~3배 더 오래 걸려 5초 제한을 초과할 수 있습니다.
일반 BroadcastReceiver의 onReceive()에서 10초입니다. 포그라운드 서비스의 제한은 20초이고 ContentProvider에는 명시적 제한이 없지만 메인 스레드를 5초 이상 차단하면 여전히 ANR이 발생합니다.
모든 디버그 빌드에서 StrictMode를 활성화하고 Firebase Crashlytics를 통한 모니터링을 추가하며 ANR 발생 시 adb bugreport를 사용하세요. 불규칙한 ANR은 종종 경합 조건이나 특정 네트워크 상태와 관련됩니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.