본문 바로가기

프로그래밍/안드로이드

ANR

ANR(Application Not Responding)이란?

ANR은 안드로이드 애플리케이션의 메인 스래드가 차단되는 경우에 발생하는 것입니다. 포그라운드 상태일때 사용자에게 ANR이 발생한 것을 알려주고 강제종료를 할 수 있도록 창을 표시합니다.

메인 스레드

애플리케이션이 실행되면 시스템에서 애플리케이션 실행의 스레드가 실행되며 이를 메인 스레드라고 합니다. 메인 스레드UI 스레드라고 불리기도 하는데 대부분의 경우에서 인터페이스와 상호작용을 담당하기 때문입니다.

모든 상황에서 메인 스레드가 UI 스레드는 아니라고 합니다.

ANR이 발생하도록 한 이유

ANR을 발생하도록 한 정확한 이유는 말씀드리기 어렵지만 예상하는 것은 안드로이드는 사용자와의 상호작용을 중요하게 생각하기 때문입니다.

만약 사용자가 애플리케이션을 사용하는데 버튼을 누르고 아무런 반응이 없다면 사용자는 애플리케이션이 동작하지 않는다고 생각할 것입니다. 애플리케이션의 내부적으로는 동작하고 있을지는 모르지만 사용자 입장에서는 동작하지 않는 것이기 때문에 불편함을 느끼고 해당 애플리케이션을 사용하지 않을 것입니다.

ANR이 발생하는 조건

아래와 같은 상황일때 메인 스레드가 차단됩니다.

  • 사용자의 입력을 애플리케이션이 5초 이상 반응하지 못할 때
  • 브로드캐스트 리시버가 상당한 시간동안 작업을 완료하지 못할 때
  • 서비스에서 20초 이상 메인스레드를 이용하여 작업할 때

사용자의 입력을 애플리케이션이 5초 이상 반응하지 못할 때

메인 스레드에서 5초 이상을 다른 작업을 하고 있어도 바로 ANR이 발생되지는 않습니다. 사용자와의 상호작용을 5초 이상하지 못할 때 ANR이 발생합니다.

예를들면 누르면 10초 동안 sleep()햐는 버튼을 사용자가 여러 번 누른 경우를 생각해봅시다. 버튼을 처음 한 번 누르게 되면 sleep()을 통해 10초 동안 메인 스레드가 정지하여 사용자의 첫 번째 이후 버튼을 누른 것을 대기하고 있게 됩니다. 5초 이상 대기하고 있으면 애플리케이션은 ANR이 발생합니다.

사용자가 버튼을 1번만 누르게 되면 anr은 발생되지 않습니다.

브로드캐스트 리시버가 상당한 시간동안 작업을 완료하지 못할 때

브로드캐스트 리시버가 onReceive()에서 오랜 시간동안 작업을 하게되면 ANR이 발생합니다. 만약 리시버가 포그라운드로 작업하고 있다면 앞서 말한 상당한 시간은 10초정도이고 백그라운드이면 30초보다 클때 발생합니다. 또한 리시버의 goAsync()를 호출하지만 PendingResultfinish()가 불리지 않으면 ANR이 발생합니다.

// 브로드캐스트 리시버
class ANRTestReceiver : BroadcastReceiver() {
    val TAG = "ANRTestReceiver_debug"

    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "start sleep")
        // 50초 sleep
        sleep(50000)
        Log.d(TAG, "end sleep")
    }
}

// 브로드캐스트 리시버 실행
// foreground broadcast
val intent = Intent(this, ANRTestReceiver::class.java)
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
sendBroadcast(intent)

// background broadcast
val intent = Intent(this, ANRTestReceiver::class.java)
sendBroadcast(intent)

서비스에서 20초 이상 메인스레드를 이용하여 작업할 때

서비스에서 20초 이상의 메인스레드를 이용해서 작업하고 있으면 ANR이 발생합니다.

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    Log.d(TAG, "start sleep")
    // 20초 sleep
    sleep(20000)
    Log.d(TAG, "end sleep")
    return START_STICKY
}

ANR을 해결

메인 스레드의 사용을 조심해서 사용해야합니다. 메인 스레드에서 다운로드와 같은 긴 시간 동안 네트워크의 사용, 긴 시간의 I/O작업, 비동기 작업을 기다리는 등의 사용을 하면 ANR이 발생할 가능성이 높기 때문에 AsyncTask 혹은 Thread를 사용하는 것을 추천드립니다. 브로드캐스트 리시버에서 오랜 작업을 하기보다는 빠르게 작업을 처리하고 만약 작업 시간이 길면 메인 스레드를 사용하지 않는 서비스를 사용해서 처리하기 바랍니다. 메인 스레드를 사용하지 않는 서비스는 AsyncTask, Thread을 사용하거나 Service class를 사용하지 않고 IntentService class를 이용하는 것을 추천드립니다.

'프로그래밍 > 안드로이드' 카테고리의 다른 글

안드로이드 개발자 가이드  (0) 2018.02.25