티스토리 뷰
본 포스팅의 내용은 [깡샘의 안드로이드 프로그래밍]을 공부하고 작성자가 생각을 정리하기 위해서 작성한 글이므로 더욱 자세한 내용을 알고 싶으신 분은 [깡샘의 안드로이드 프로그래밍]을 강력 추천합니다!!
ANR(Application Not Responding)
ANR은 액티비티가 사용자 이벤트에 반응하지 못 하는 상황을 이야기합니다. 좀더 자세히 말하자면 액티비티가 출력된 상황에서 사용자 이벤트에 5초 이내에 반응하지 못하면 시스템에서 액티비티를 강제로 종료하게 됩니다. 사용자들은 보통 이를 버그라고 인식하게 되겠죠.
ANR은 특정 업무가 5초 이상의 시간이 걸려 사용자의 이벤트를 처리하지 못 하게 되는 경우에 발생합니다. 긴 시간이 걸리는 업무 처리가 많지 않을 것 같지만 앱을 개발하다 보면 5초 이상의 긴 시간 동안 수행하게 되는 업무처리 로직이 종종 있습니다.(주로, 네트워킹)
ANR 문제 해결방법
ANR이 발생하는 근본적인 문제는 액티비티에서 5초 이상의 업무 처리를 하느라 사용자의 이벤트를 처리하지 못 한다는 것에 있습니다.
ANR을 해결하는 방법은 액티비티의 수행 흐름(스레드)을 하나 더 만들어 주는 것입니다.
안드로이드에서의 스레드 패턴은 액티비티를 초기화하고 화면을 출력하며 사용자의 이벤트를 처리하는 메인 스레드(UI 스레드)와 시간이 오래 걸리는 작업을 처리할 1개 이상의 개발자 스레드(백그라운드, 서브) 스레드로 이뤄져 있습니다.
그렇다면 이제 스레드를 만드는 방법을 알아보도록 합시다.
스레드(Thread)를 만드는 방법
스레드를 만드는 방법은 두 가지가 있다.
- Thread 클래스를 상속받아 작성하는 방법
- Runnable 인터페이스를 구현하여 작성하는 방법
1. Thread 클래스를 상속
class MyThread extends Thread {
public void run() {
}
}
Thread를 상속받아 클래스를 하나 만들며 run( ) 함수를 재정의해서 작성하고
MyThread thread = new MyThread();
thread.start()
정의 Thread 클래스를 생성하여 start() 하면 run()에서 재정의한 로직이 실행되고 함수의 수행이 끝나면 스레드는 자동으로 종료됩니다.
2. Runnable 인터페이스를 구현
class MyThread implements Runnable {
public void run() {
}
}
Runnable 인터페이스를 구현하여 이 클래스가 스레드에 의해 처리될 내용을 가지는 클래스로 선언하고
MyThread runnable = new MyThread();
Thread thread = new Thread(runnable);
thread.start();
Thread 상속과 Runnable 구현의 차이
두 방법의 차이는 너무 당연한 얘기지만 클래스를 상속하느냐 인터페이스를 구현하느냐의 차이가 있습니다.
자바는 다중 상속이 불가능한 언어입니다. 따라서 Thread를 상속받으면 다른 클래스를 상속받을 수가 없습니다.
따라서 코드 확장성이나 재사용성면에서 Runnable 인터페이스를 구현하는 쪽이 이점을 가져갈 수 있습니다.
그 외에도 메모리적인 부분이나 코드가 느슨하게 결합된다는 장점이 있다고 하는데 아직 크게 와닿지 않는 부분이네요. 궁금하신 분은 아래 링크를 참조해주시면 되겠습니다.
스레드 제어 함수
- start( ) : run( ) 함수에 구현한 로직을 개발자 스레드에서 실행합니다.
- sleep( ) : 인자로 넣은 시간만큼 멈추었다가 다시 동작하게 됩니다.
- wait( ) : 스레드가 여러 개 존재하면서 서로간의 작업을 일정한 순서에 따라 진행하고 싶을 때 사용하며 대기 상태가 되어 스스로 수행 상태가 될 수 없습니다.
- notify( ) : 대기 상태가 된 다른 스레드를 notify( ) 함수를 이용해서 깨워줘야 다시 동작합니다.
핸들러
이제 개발자 스레드를 사용하는 방법을 알았지만 개발자 스레드에서도 치명적인 문제가 있습니다. 바로 안드로이드 시스템에서 액티비티를 수행하면서 발생시킨 UI 스레드가 아닌, 개발자 스레드에서 런타임 때 액티비티의 뷰에 접근하면 에러가 발생한다는 것입니다.
하지만, 안드로이드 앱을 만들다보면 개발자 스레드에서 뷰를 업데이트 해야할 때도 분명히 있습니다. 이 때 사용되는 클래스가 핸들러(Handler)입니다.
핸들러를 활용하는 방법도 두 가지가 있습니다.
- post( )
- sendMessage( )
1. post( ) 함수를 이용하는 방법
Handler handler = new Handler();
class UIUpdate implements Runnable {
@Override
public void run() {
textView.setText("Hello, weekyear")
}
}
class MyThread implements Runnable {
public void run() {
Thread.sleep(1000);
handler.post(new UIUpdate());
}
}
- Handler 클래스의 객체를 기본 생성자를 이용하여 생성합니다.
- 뷰와 관련된 작업을 담당하는 Runnable을 구현한 클래스를 준비합니다.
- 개발자 스레드에서 뷰와 관련된 작업이 필요하면 Handler의 post( ) 함수를 호출하여 UI 스레드에게 작업을 의뢰합니다.
2. sendMessage( ) 함수를 이용하는 방법
class MyThread implements Runnable {
public void run() {
Message message1 = new Message();
message.what = 1;
message.arg1 = 29;
handler.sendMessage(message)
Thread.sleep(10000);
Message message = new Message();
message.what = 2;
message.obj = "ByeBye";
handler.sendMessage(message1);
}
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
textView.setText(String.valueOf(msg.arg1))
} else if (msg.what == 2) {
textView.setText(String.valueOf(msg.arg1))
}
}
}
- sendMessage( ) 함수로 요청할 때 Message 객체가 매개변수로 사용되는데, Message는 뷰 작업을 의뢰할 때 UI 스레드에 넘기는 데이터를 담는 객체입니다.
- what : int 형 변수로 Message의 타입을 구분하기 위해 사용합니다.
- obj : Object 타입의 변수로 스레드에 넘길 데이터입니다.
- arg1, arg2: int형으로 UI 스레드에 데이터를 담아서 넘겨줍니다.
- handleMessage( )에서 sendMessage를 통해 받은 데이터를 활용하여 UI 뷰를 업데이트할 수 있습니다.
'Programming > 안드로이드(Android)' 카테고리의 다른 글
[안드로이드] ProgressBar에 애니메이션 적용 (0) | 2021.05.13 |
---|---|
[안드로이드] 구글 플레이 콘솔 기기 0대에서 사용 가능 (uses-feature) (0) | 2021.05.11 |
release 모드 Sha-1 키 얻는 법 (0) | 2021.05.07 |
[안드로이드] Waiting For Debugger가 계속 뜨고 앱이 시작되지 않을 때 (0) | 2021.04.30 |
[안드로이드] 갤러리(Gallery)의 Image uri를 가져오고 실제 기기의 저장 주소로 변환하는 법 (0) | 2021.04.27 |