Handler

Handler는 메시지 드리븐 스레드에 메시지를 등록시켜주는 “전달자 클래스”다.

를 설명하기 앞서 안드로이드의 “Message driven thread”에 대해 설명을 어느정도 짚고 가야겠네요.

안드로이드에서 “Message driven thread”를 만들려면 아래와 같은 요소가 필요합니다.

- MessageQueue(큐)

- Loopper(실행기)

MessageQueue는 처리할 메시지들을 보관해 놓는 큐이며, Looper는 무한루프를 돌면서 메시지큐를 처리하는 실행기입니다.

기본적으로 UI-Thread는 MessageQueue와 Looper를 모두 가지고 있으므로,

초보 개발자들이 보기에는 스레드에서 UI-Thread로 메시지를 보내는 용도로 생각하게 됩니다. (이글을 쓰기 전까지 나도 이랬…)

게다가 초보개발자들이 오인하는 가장 큰 이유는 Handler의 생성자에 기인하고 있습니다.

Handler handler = new Handler();

물론 Looper를 직접 받는 생성자도 있지만, 위처럼 아무것도 없는 기본 생성자가 있으며,

어떠한 인수를 넘겨주지 않았음에도(메시지큐, Looper를 넘겨준 적이 없다?) Handler는 잘 동작했지요…;;

그 이유는 UI-Thread의 Thread 저장소에 MessageQueue와 Looper가 저장되어 있기 때문이죠.

아래 코드는 Handler코드와 Looper코드의 일부입니다.

Handler )

public Handler(Callback callback, boolean async) {
 ……

mLooper = Looper.myLooper(); // 아래 코드를 통해 스레드로컬에서 가져옴을 알 수있다.
 if (mLooper == null) { // Looper가 없으면 런타임을 통해서 예외가 발생됨을 유추할 수 있다.
 throw new RuntimeException(
 “Can’t create handler inside thread that has not called Looper.prepare()”);
 }
 ……
 }

Looper )

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); // 스레드 저장소

…..

public static Looper myLooper() {
 return sThreadLocal.get(); //스레드 로컬에서 Looper를 가져옴을 확인할 수 있다.
 }

위와같이 Looper를 받는 코드가 일반 개발자들에게 숨겨져(?) 있기 때문에,

초보개발자들은 루퍼의 존재를 잘 모른 상태에서 Handler를 사용하게 되는 셈이죠.

루퍼를 일일이 대입할 필요가 없어 개발 편의성이 높아졌지만

내부를 잘 모르게 되어 아래와 같이 일반 스래드 내에서 Handler를 생성하게 되면 백퍼센트 뻗어버리게됩니다.

bad example )

new Runnable() {
 @Override
 public void run() {
 new Handler(); // Looper, 메시지큐가 없어서 뻗게됨!
 }
 };

세줄 요약 )

1) Handler는 메시지큐에 메시지를 등록해주는 대리자이다.

2) Hanler의 내부적인 특이점으로 인하여, UI-Thread로 메시지를 스위칭해주는 객체로만 오인할 수 있다.

3) 아무준비 없이 스래드 내부에서 Handler생성하지 말라…..

3번 요약에 대한 준비요소는, HandlerThread 에서 설명하도록 하겠습니다.

[출처] Handler|작성자 루미주인