안드로이드 스튜디오 ANR 에러가 발생하는 이유와 해결하기

Posted by 앱해피
2015. 6. 16. 14:41 안드로이드 스튜디오

 

안드로이드 프로그래밍을 하다보면 ANR(Android Not Responding)이라는

 

이름을 갖는 에러가 참 많이 발생됩니다.  ANR 에러가 발생하는 이유에 대해 알아보고

 

이를 피할 수 있는 방법을 알아보겠습니다.

 

 

 

 

Case 1 액티비티에서 발생하는 ANR 에러

 

public void onClick(View v) 
{
        switch (v.getId()) 
        {
            case R.id.start_count_btn :
            {
                while( true) 
                {
                    mCurNum ++;

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            break;
       }
}

위에 나온 코드는 MainActivity라는 액티비티에서 버튼이 클릭될 때 호출되는 함수의 일부입니다.

 

ID값이 R.id.start_count_btn인 버튼을 클릭할 때, 그와 관련된 while문에서는 1초 간격으로 계속

 

앱을 정지시킨다는 것을 확인하실 수 있습니다.

 

그 전에, 메인스레드(Main Thread)에 대해서 알아보겠습니다. 이것의 가장 대표적인 기능이라면

 

Activity에서 실행되는 여러가지 콜백함수들을 호출하여 처리하는 역할을 담당하고 있습니다.

 

또한, 우리가 스마트폰으로 볼 수 있는 대부분의 화면(뷰)은 메인스레드가 그려주는 것입니다.

 

이런 메인스레드의 역할을 생각하면 위의 코드의 문제점이 무엇인지 명확해 집니다.

 

다양한 뷰를 그려주는 역할과 콜백함수를 처리하는 역할을 하는 메인 스레드를 while문 안에서

 

무한루프를 처리하도록 지시했기 때문에 메인스레드는 자신에게 부여된 다른 작업을 처리할 수 없게 되고

 

그에 따라서 ANR 에러를 발생시키게 되는 것입니다.

 

public void onClick(View v) 
{
        switch (v.getId()) 
       {
            case R.id.start_count_btn: {
                mCountThread = new Thread("Count Thread") {
                    public void run() {
                        mCurNum++;

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };

                mCountThread.start();
            }
            break;
      }
}

 

 

ANR이 발생하는 문제를 해결하기 위해서는 위와 같이 별도의 쓰레드(Thread)를 생성해서 따로 자신이 원하는

 

작업을 처리해주면 됩니다. 이처럼 별도의 쓰레드를 생성해서 처리해야 하는 작업은 대충 다음과 같이 나뉘어 집니다.

 

1. 주기적으로 오래 처리되야 하는 작업 등 (코드 내부에서 반복문을 돌거나 스레드를 일시정지 시켜야 하는 경우)

 

2. 네트워크와 관련된 작업 등 (네트워크 연결 상태에 따라 시간이 무한정 늘어날 수 있음)

 

 

 

 

Case 2 서비스에서 발생하는 ANR 에러

public class CountService extends Service 
{
    private int mCurNum = 0;
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
    {
        while (true) {
            mCurNum++;

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                break;
            }
        }
        
        return START_STICKY;
    }
    
    ..............
}

 

이번에는 액티비티(Activity)가 아닌 Service클래스를 상속받은 CountService에서 동일한 기능을 하는 코드를

 

확인할 수 있습니다. 이것과 관련된 서비스가 생성되면 onStartCommand()라는 콜백 메소드가 호출된 이후

 

함수 안에 있는 코드가 실행 될 것 입니다. 예상과는 다르게 위의 코드에서도 ANR 에러가 발생한다는 것을 알 수 있습니다.

 

우리는 지금까지 서비스라는 것을 생성하고, 백그라운드 상태에서 처리될 것들을 정의했습니다. 왜 백그라운드에서

 

처리되는 서비스가 ANR을 일으키는지 이해하지 못할 겁니다. 왜냐하면 이제까지 서비스와 메인스레드는 하는 역할이

 

구분되어 있다고 생각했기 때문입니다.

 

하지만 확실히 기억해야 할 것은, 서비스가 별도의 컴포넌트로 구분이 된다 하더라도 서비스의 모든 콜백 함수들은

 

메인스레드에 의해서 처리가 됩니다. 즉, 서비스의 onStartCommand()라는 함수 역시도 메인스레드가 처리하기 때문에

 

무한루프에 빠지도록 코드를 작성하면 안된다는 것입니다. 만약 onStartCommand()라는 함수에서 계속해서 동작해야 하는

 

기능을 구현하고 싶다면 별도의 스레드를 통해서 그와 관련된 기능을 구현해야 합니다.

 

public class CountService extends Service
{
    private int mCurNum = 0;
    private Thread mCountThread = null;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        if (mCountThread == null ) {
            mCountThread = new Thread("Count Thread") {
                public void run() {
                    while (true) {
                        mCurNum++;

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            break;
                        }
                    }
                }
            };

            mCountThread.start();
        }

        return START_STICKY;
    }
    
    ..............
}

 

비록 백그라운드에서 처리되는 서비스이지만 오래 걸리는 작업을 처리해야 할 때에는 별도의 쓰레드를 생성하고

 

쓰레드에서 처리되도록 구성해야 합니다. 이와 같은 방법으로 ANR 발생을 예방할 수 있습니다.

 

 

 

 

앱을 구현하다가 ANR 에러가 발견됐다면 메인 스레드가 담당하는 코드에서

 

오래 걸리는 작업을 하는 부분을 찾아  수정하는 것이 핵심입니다.