본문 바로가기
Android/Android 기초

[Android] 핸들러(Handler)와 루퍼(Looper)

by 태크민 2025. 2. 27.

안드로이드에서 Thread

안드로이드에서의 메인 스레드(Main Thread, UI Thread)란?

  • 앱이 실행됐을 때 시스템에서는 메인(Main)이라고 불리는 스레드를 생성한다.
  • 메인스레드는 안드로이드 이벤트 생성 및 처리를 담당할 뿐 아니라 안드로이드에서 발생되는 여러 이벤트를 그와 관련된 위젯으로 연동시키는 중요한 역할을 수행한다.
  • 또한 안드로이드에서 제공하는 다양한 뷰와 위젯을 표현하는 역할과 사용자로 하여금 그것을 사용할 수 있게 해 주어 UI 스레드라고도 불린다.

앱에 메인 스레드만 존재한다면?

  • 앱이 단일 스레드 즉 메인 스레드만 존재하는 모델에서는 형편없는 성능을 낳게 된다.
  • 메인 스레드에서 모든 작업을 처리한다면 네트워크 처리 및 데이터베이스 쿼리와 같이 오래 걸리는 작업을 하는 동안 UI와 관련된 작업을 처리하지 못하게 된다.
  • 이것이 문제가 되는 이유는 오랜 시간 UI 관련된 작업을 처리하지 못하면 ANR(Application Not Responding) 에러가 발생하고 그 즉시 앱이 정지되기 때문이다.

왜 UI 는 싱글 쓰레드 모델로 동작할까?

  • 만약 UI가 멀티스레드에 의해 변경되는 환경이라면 여러 스레드에서 UI를 변경하려고 시도하는 상황이 발생할 수 있다.
  • 이는 어떤 결과가 나타날 지 모르게 만든다.
  • 즉 동작의 무결성을 보장하지 못한다.
  • 따라서 메인 스레드는 싱글 스레드 모델로 동작하여 오직 메인 스레드에서만 UI 관련 동작을 할 수 있게끔 한다.

스레드 간 통신의 필요성

여러 스레드의 결과는 보통 UI를 업데이트하는 데 사용된다.

 

이럴 때는 스레드 간 통신이 필요하다. 안드로이드에서는 스레드 간의 통신을 위해 Looper, Handler라는 도구를 제공한다.

 


루퍼(Looper)

하나의 쓰레드에는 오직 하나의 Looper 를 가지며, Looper 는 오직 하나의 쓰레드를 담당한다.

각 쓰레드의 Looper 내부에는 MessageQueue라는 것이 존재하는데, 여기에는 해당 스레드가 처리해야 할 동작들이 '메세지'라는 형태로 하나씩 쌓이게 된다. (FIFO 방식)

Looper는 궁극적으로 MessageQueue에 들어오는 메세지들을 하나씩 꺼내어 이를 적절한 Handeler로 전달하는 역할을 한다.

 

루퍼는 메세지 큐가 비어 있는 동안 아무 행동도 하지 않고, 메서드가 들어오면 해당 메시지를 꺼내 작업을 수행한다.

스레드는 기본적으로 생성될 때 루퍼를 가지지 않고 Looper.prepare() 메서드를 호출해야지 루퍼가 생성된다.

하지만, 메인 스레드는 기본적으로 MainActivity 가 실행됨과 동시에 자동으로 Looper 가 돌기 시작한다.

메인 쓰레드의 Looper 는 보통 UI 작업을 위한 메세지를 처리하게 된다.

 

루퍼(Looper) 관련 메서드

메서드 명 반환 타입 내용 설명
prepare() void 루퍼를 생성한다.
loop() void 무한히 루프를 돌며 메세지 큐에 쌓인 Message 객체나 Runnable 객체를 핸들러에게 전달한다.
quit() void 루프를 종료한다.

 


핸들러(Handler)

Handler 는 명칭에서 알 수 있듯 뭔가를 다루는 녀석인데, 특정 메세지를 Looper 의 MessageQueue 에 넣거나, Looper 가 MessageQueue 에서 특정 메세지를 꺼내어 전달하면 이를 처리하는 기능을 수행한다. 중간 다리 역할을 수행한다.

메시지 큐(Message Queue): 단방향 연결 리스트로 Message 객체를 Queue 형태로 관리하는 자료구조이다.

 

Looper로 메시지를 전달하는 경우

Message 객체를 생성하여 이를 전달하는 방식으로 구현한다.

  • sendMessage() 메소드를 통해 메시지 큐에 Message 객체를 적재할 수 있다.
  • post로 시작하는 메서드들을 통해 Runnable 객체를 직접 적재할 수 있다.

Looper로부터 메시지를 전달받는 경우

Looper 가 메세지 큐에서 메세지 하나를 딱 꺼냈을 때,

  • Runnable 객체가 담겨있다면
    → 해당 Runnable의 run() 메소드를 호출하여 작업을 실행할 수 있다.
    post를 통해서 전달된 Runnable 객체는 해당 핸들러가 연결된 스레드에서 실행된다.
  • Message 객체가 담겨있다면
    → 해당 메시지 내부의 Handler가 갖고 있는 handleMessage() 메소드를 호출함으로써 해당 Handler가 메시지를 전달받을 수 있다.

핸들러(Handler)를 통한 스레드간 통신

 

동작 순서

  1. “워커 스레드”가 UI처리를 위해 ”메인 스레드의 Handler” sendMessage() 메서드로 메시지를 전달한다.
  2. 해당 메세지는 “메인스레드의 Message Queue”에 저장된다.
  3. 메인 스레드의 Looper”가 차례대로 메시지를 꺼내 “메인 스레드의 Handler”의 handleMessage() 로 전달된다.
  4. “메인스레드의 Handler”가 UI 작업을 수행한다.

Handler 관련메서드

메서드 명 반환 타입 내용 설명
obtainMessage() Message 핸들러 자신으로 지정된 메세지 객체를 리턴
sendMessage(msg: Message) boolean 메세지 큐에 Message 객체 전달
post(runnable: Runnable) void 메세지 큐에 Runnable 객체 전달
sendEmptyMessage(what: Int) boolean 간단하게 what 값을 통해서 메시지를 보낼 때 사용
removeMessages(what: Int) void 전달한 what 코드 메세지를 메세지 큐에서 삭제
handleMessage(msg: Message) void 루퍼를 통해 메제지 큐에서 꺼낸 Message 처리

 

Handler 사용코드

handler = object : Handler() {
    override fun handleMessage(msg: Message) {
        super.handleMessage(msg)

        if (msg.what === START_CODE) {
            thread.start()
        } else if (msg.what === PROGRESS_CODE) {
            textView.text = "Count : ${msg.arg1}"
        }
    }
}

 

Message를 보내는 것과 Runnable을 보내는 것은 어떤 차이가 있는 것일까?

메시지(Message)와 핸들러(Handler)를 사용하여 스레드 통신을 수행하는 주 목적은, "핸들러를 통해 데이터를 전달하여, 전달된 데이터 처리를 위해 작성된 대상 스레드의 코드가 실행되도록 만드는 것"이다. 이를 위해, 메세지 객체(object, arg1, arg2)에 값을 채워 수신 스레드의 핸들러에 보내고, 수신 측 스레드는 handleMessage()메서드를 오버라이드하여 수신된 메세지 객체를 처리하기 위해 작성된 코드를 실행하는 것이다.

 

그런데 메세지(Message)객체를 사용하는 방법에는 조금 번거로운 절차가 필요하다. 메시지에 저장된 데이터 종류를 식별하기 위해 값을 상수로 지정해야 하고, handleMessage()에서는 상수값에 따른 처리 코드를 조건문으로 작성해야 한다. 그리고 메세지를 보내는 측도 전달할 데이터의 종류에 따라 별도의 메시지 객체를 구성하고 값을 채워 보내야 한다. 이는 오직 대상 스레드에 작성된 코드를 실행하기 위해서다.

 

이때 만약 이러한 번거로운 과정을 거치지 않고 "실행코드"를 바로 보내면 어떨까? 즉 핸들러에 실행 코드가 담긴 객체를 보내고, 대상 스레드에서는 수신된 객체 코드를 바로 실행하게 만드는 것이다.

 

이때 이 "실행코드"가 담긴 객체가 Runnable 객체이다.

 


참고자료

https://jminie.tistory.com/186#4.%20%EB%A9%94%EC%8B%9C%EC%A7%80%20%ED%81%90(Message%20Queue)

 

안드로이드 [Kotlin] - 핸들러와 루퍼(Handler & Looper)

안드로이드에서 Thread 안드로이드에서의 메인 스레드(Main Thread, UI Thread)란? 앱이 실행됐을 때 시스템에서는 메인(Main)이라고 불리는 스레드를 생성한다. 메인스레드는 안드로이드 이벤트 생성 및

jminie.tistory.com

https://velog.io/@haero_kim/Android-Looper-Handler-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90

 

[Android] Looper & Handler 기초 개념

안드로이드 멀티 쓰레딩 공략하기

velog.io