본문 바로가기

안드로이드/알아두기

[안드로이드] Handler와 Looper 에 대하여

1. Handler와 Looper에 대해 알아보기 전에

핸들러와 루퍼에 대한 설명전에 왜 핸들러와 루퍼에 대하여 알아야 하는지 알아보자

사진출처 : https://jw910911.tistory.com/54


위 그림을 보자. 2개의 스레드 모두 값은 다르지만 textView.setText() 동작을 한다. 근데 스레드들이 병렬구조로서 동시에 textView에 접근하여 setText()를 한다면, 오류가 발생하게 된다. 그래서 안드로이드에서는 메인 스레드만 UI 작업을 처리할 수 있게 해두었다. 그래서 메인 스레드를 UI 스레드라고도 불린다. 하지만 메인 스레드가 UI 스레드라고 해서 오직 UI 작업만 처리하는게 아니다. BroadCast Receiver, Service 등과 같은 작업도 물론 UI 스레드에서 처리된다. 다만 UI 작업은 오직 메인 스레드에서만 처리되니까 UI 스레드라고 하는것이다.

그렇다면, UI 스레드가 아닌 서브 스레드에서 UI 작업은 처리하지 못하냐고 물어보면 그건 또 아니다. 서브 스레드에서는 UI 작업을 처리하기 위해서 핸들러와 루퍼를 사용하여 UI 작업을 처리하도록 메인 스레드에 메시지를 보내서 UI 작업을 처리하게 된다. 그리고 이러한 메커니즘을 정확히 알기 위해서 핸들러와 루퍼에 대하여 알아야 한다.


2. Handler & Looper

사진 출처 : https://itmining.tistory.com/5


위 사진 중간의 파란색인 Handler를 보면서 Handler에 대해 설명해보겠다.
핸들러 아래에 보면 handleMessage(), sendMessage()라는 두 메소드 호출이 보인다. 근데 두 메소드 다 공통적으로 Message라는 단어를 포함한다. 그것으로 미루어 보아 핸들러는 Message 객체를 처리한다는 것을 알 수 있다.
sendMessage() 메소드의 플로우를 한 번 보면, message가 MessageQueue에 queueing 되는데, message가 아닌 runnable도 포함되어 있는 것을 확인할 수 있다. 이것으로 미루어 보아 우리는 핸들러가 Runnable 객체 또한 처리한다는 것을 알 수 있다. 위 사항들을 정리해보면 아래와 같다.

  • Handler는 Message와 Runnable 객체를 처리한다.
  • 서브 스레드에서 UI작업을 처리하고 싶으면, handler의 sendMessage()를 사용하여 메인 스레드의 MessagingQueue에 UI 작업 처리에 대한 메시지를 보낸다.
  • MessagQueue에서는 핸들러에 handleMessage()를 이용하여 메시지를 처리한다.
  • Handler는 스레드에서 메시지를 주거나, MessagQueue에서 handle해야 한다. 하지만 메시지를 주지 않으면 아무것도 할 수 없는, 른 객체에 굉장히 의존적이라는 것을 알 수 있다.


이번에는 Looper에 대해서 설명해보겠다.
사진을 보면 알 수 있듯이 하나의 스레드에는 하나의 루퍼만 존재할 수 있다. 그래서 스레드는 오직 하나의 루퍼만, 루퍼는 오직 하나의 스레드만 가질 수 있다. 이 루퍼의 특징은 아래와 같다.

  • 특정 스레드를 전담하는 루퍼는 오직 하나밖에 없다.
  • 루퍼에는 MessageQueue가 있다.
  • 해당 MessageQueueempty 상태일 경우 Looper는 아무 동작도 하지 않는다.
  • Looper는 Loop + er 의 합성어로, 계속해서 작업을 반복적으로 수행하기 때문에 이러한 이름이 붙었다.



아래 코드를 보자.

Thread t = new Thread(Runnable(){ @Override public void run(){ Looper.prepare(); handler = new Handler(); Looper.loop(); } }); t.start();


특정 스레드에서 루퍼를 포함시키려면 Looper.prepare()를 통해서 루퍼를 준비시키고, handler를 만들어 메시지를 핸들링하고, 루퍼를 루프시켜 해당 스레드에서는 루퍼가 동작을 반복하게 지시했다. 이후 Message가 Queue에 enQueue되면, 메시지를 처리하게 된다. 다만 해당 루퍼는 더이상 동작하지 말아야 한다면 onDestroy에서 Handler.getLooper.quit()을 해줘야지 메모리 누수가 일어나지 않는다.