Looper와 Handler에 대하여

Aiden
6 min readAug 26, 2019

--

위의 자료가 공부하기에 제일 적합했던 것 같다. 나의 포스팅은 위의 자료를 정리한 것이니 위의 자료를 꼭 한번 읽어 보기를 추천한다.

위의 자료를 읽고 Android의 Looper와 Handler 공식문서를 읽어 보면 더 이해하기가 쉬울 것이다.

Looper와 Handler가 태어난 이유

한마디로 정의하면, Looper와 Handler는 스레드간의 통신을 위해 태어났다.

그럼 Android에서 Looper와 Handler를 자주 만나는 이유는 무엇일까?

이 모든 것은 Android UI에서 시작되었다

AndroidUI 특징

Android UI는 싱글 스레드 모델을 따르고 있다.

싱글 스레드 모델 : 안드로이드 화면을 구성하는 뷰나 뷰그룹을 하나의 스레드에서만 담당하는 원칙

싱글 스레드 모델의 규칙은 두가지가 있다.

첫째, 메인 스레드(UI 스레드라고도 불림)를 블럭하지 말 것

둘째, 안드로이드 UI 툴킷은 오직 메인 스레드(UI 스레드)에서만 접근할 수 있도록 할 것

둘째 조건때문에 메인 스레드가 UI 스레드라고도 불리우는 것이다.

만일 긴 시간이 걸리는 작업을 메인 스레드에서 작업한다면 어떤 결과가 초래할까? 메인 스레드에서는 UI도 챙겨야하는데, 다른 긴 작업까지 겹치면 앱의 반응속도가 상당히 느려질 것이고, 최종적으로는 반응이 없다는 상태인 ANR(Application Not Responding)이 나오며 사용자는 부정적인 경험을 하게될 것이다.

따라서 시간이 걸리는 작업들은 여분의 스레드를 만들어 메인 스레드와 분리해야했다. 자연스럽게 메인 스레드와 기타 스레드들이 많아지면서 스레드간 통신이 필요해졌다.

Android 메인 스레드에서 Looper와 Handler가 필요한 이유

자 이제 메인 스레드와 다른 스레드들이 분리되었다는 것은 이해했다. 근데 왜 메인 스레드에서만 UI이 작업하게 만들어 놓은 것일까?

싱글 스레드 모델을 따르지 않는다고 가정해보자. 다른 스레드들과 메인 스레드가 특정 TextView의 setText 메소드를 호출하는 경우 어떤 것부터 처리해야할 것인가?

간단히 상상을 해보면, 엄청난 맛집에 대기나 예약 시스템이 없다고 가정해보자. 어떤 손님을 받아야할지 주인도, 내차례인지 손님들도 우왕좌왕 할 것이다. 결국 줄을 세울 수 있는 시스템(종이노트에 순서를 적든, 앱으로 예약을 하든 등등)이 필요한데, 이 시스템이 Looper와 Handler인 것이다.

결국 동기화 이슈 때문에 메인 스레드에서만 UI작업을 할 수 있게 만들었고(싱글 스레드 모델), 메인 스레드와 다른 스레드간의 통신을 위해 Looper와 Handler가 필요한 것이다.

Android 메인 스레드에서 Looper와 Handler는 어떻게 일해?

메인 스레드는 기본적으로 Looper를 가진다

*Java에서 기본 제공하는 스레드는 Looper가 기본적으로 포함되어있지 않고, Android에서 제공하는 HandlerThread는 기본적으로 Looper를 가진다

Looper는 Message Queue라는 선입선출의 Queue를 가진다. Message Queue는 Message와 Runnable 타입의 객체가 저장된다.

Looper는

1. 주기적으로 Message Queue를 확인하여,

2. Message나 Runnable 객체가 존재한다면 Handler로 보내 처리를 요청한다.

Handler는

1. Looper가 보낸 Message나 Runnable 객체를 처리하거나,

2. 다른 스레드에서 메인스레드에 처리를 요청한 Message나 Runnable 객체를 메인스레드 Looper의 Message Queue에 넣는다.

비유적으로 말하면, Looper는 제조 공장의 감독관이고, Message Queue는 일감 리스트, Message와 Runnable 객체는 일감, Handler는 영업과 제조까지 하는 근로자인 것이다.

Message와 Runnable 객체의 차이점 : Message는 int나 Object같이 스레드 간 통신할 내용을 담는다면, Runnable은 실행할 run() 메서드와 그 내부에서 실행될 코드를 담는다

Looper를 더 자세히 들여다 보자

메인 스레드가 아닌 스레드에서 Looper를 사용하려면 여러가지 메소드를 알아야한다.

기본 생성 및 사용 설정 메소드

prepare : Looper를 생성

loop : Looper 활동개시

중단 메소드

quit : Looper 즉시 종료

quitSafely : 현재 Message Queue에 쌓인 일감을 처리한 후 종료

Handler를 더 자세히 들여다 보자

크게 Looper에서 보낸 일감을 처리하는 메소드와 Looper로 일감을 전달하는 메소드의 카테고리로 나눌 수 있다.

일감을 처리하는 메소드

handleMessage : Looper가 전달한 Message나 Runnable 객체를 처리

일감을 전달하는 메소드

일감을 전달하는 메소드는 Message 객체를 전달하느냐, Runnable 객체를 전달하느냐에 따라 sendMessage 계열(Message)과 post 계열(Runnable)로 나뉘게 된다.

sendMessage 계열

sendMessage : Message Queue에 Message 객체를 전달

sendMessageAtFrontOfQueue : Message Queue 맨앞에 Message 객체를 전달

sendMessageDelayed : 일정시간 지연 후, Message Queue에 Message 객체를 전달

post 계열

post : Message Queue에 Runnable객체를 전달

postAtFrontOfQueue : Message Queue 맨앞에 Runnable객체를 전달

postDelayed : 일정시간 지연 후, Message Queue에 Runnable객체를 전달

마무리

오늘은 Looper와 Handler의 태어난 역사에서부터, 작동하는 방식, 내부 메소드 등을 확인해보았다. Looper와 Handler에 대해서 간략한 지식을 가지고 있었는데, 이번에 포스팅하면서 많은 것을 배우고, 생각하고, 정리할 수 있어서 좋은 경험이었다.

--

--

Aiden

안드로이드 개발자(개인 공부용도의 블로그)