본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[android/안드로이드] Handler 의 내부적 진실.

by 돼지왕 왕돼지 2012. 10. 5.
반응형





제목은 좀 거창하지만, Handler 에 대해 겉핥기가 아닌, 속까지 보자는 의도에서 작성하는 포스트입니다.

사실 저는 "김상형" 씨의 안드로이드 관련 책에서 Looper, MessageQueue, 그리고 Handler 에 대한 자세한 설명을 읽기는 했지만, 살짝 머리에서 미끄러져 있던 진실들과, 그리고 정확하게 이해하지 못하고 있던 내용들을 한번 열거해봅니다.


1. Handler 는 항상 특정 스레드와 연결되어 있어야 정상적으로 작동하고, 해당 스레드에는 메세지를 담을 수 있는 MessageQueue 와 Handler 로 메세지를 전달해줄 Looper가 있어야 한다. 모든 Thread 가 다 MessageQueue와 Looper가 있는 것은 아니다. Main Thread는 기본적으로 두 개 다 가지고 있다. 그래서 메인스레드에서는 new Handler() 를 통해 Handler 를 생성해도 잘 작동하는 것이다.



2. 기본생성자를 통해 Handler 를 생성하면, 새롭게 생성된 Handler는 해당 Handler의 생성자가 호출된 바로 그 스레드의 MessageQueue 그리고 Looper 에 자동으로 연결됩니다. 위에서 언급했듯 모든 Thread 에 MessageQueue와 Looper 가 있는 것은 아닙니다. 3번에서 그 상황에 대해 알아봅니다.



3. Looper 가 없는 스레드에서 Handler 를 생성하려 하면, 아래와 같은 에러가 난다.

ERROR/AndroidRuntime(): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

 

4. Looper 는 한 Thread 에 하나만 존재하며, 하나의 MessageQueue 와만 연결된다. ( Looper는 MessageQueue의 내용을 지속적으로 확인해서 Handler 한테 처리하라고 던져준다. ) Looper는 여러개의 Handler와 연결될 수 있다. 이것이 가능한 이유는 Message로부터 어떤 Handler 에 전달되야 하는 메세지인지 알 수 있기 때문이다. Looper는 여러 Handler와 연결될 수 있지만, 즉 한 thread 에서 여러개의 Handler를 생성할 수 있지만, 한 Handler는 하나의 Looper에만 연결된다.



5. Looper 를 생성하는 방법은 생성한 Thread 에서 Looper.prepare() 를 호출해 주고, Looper.loop() 을 실행해주는 것. ( 필자는 개인적으로 Looper.prepare() 를 MessageQueue와 Looper 객체의 생성으로.. Looper.loop() 을 Thread.run() 과 같은 looper 작동으로 이해했다. ) Looper는 무한루프를 도므로, Handler를 더 이상 사용하지 않을 때에는 Looper.quit() 을 호출해주어야 한다.


Thread thread = new Thread(new Runnable(){

   @Override

   public void run() {

      Looper.prepare();

      handler = new Handler();

      Looper.loop();

   }

});

thread.start();  

 

 

6. Looper를 생성하는 간단한 방법은 HandlerThread 를 사용하는 것이다. HandlerThread는 기본적으로 Looper를 가지고 있고, 해당 Thread를 start 시키면 자동으로 loop도 돈다.

HandlerThread handlerThread = new HandlerThread("HandlerName");

handlerThread.start();

Handler handler = new Handler( handlerThread.getLooper() );








 


반응형

댓글