이번 게시글에서는 안드로이드에서의 MessageQueue에 대해 알아보고자 합니다.
MessageQueue란?
MessageQueue는 특정 스레드에서 실행될 작업들(Message, Runnable)의 목록을 저장하는 큐입니다.
안드로이드 앱에서는 버튼 클릭, UI 갱신 등 다양한 이벤트가 발생합니다. 이런 작업들을 한 번에 처리하지 않고, 메시지 형태로 큐에 넣어 순서대로 처리하기 위해 MessageQueue가 사용됩니다.
당연하게도, MessageQueue만으로는 원하는 작업을 처리할 수 없고 안드로이드는 두 가지 핵심 도구인 Looper와 Handler를 사용하여 작업을 진행합니다.
Runnable
Runnable은 1개의 메서드를 갖는 함수형 인터페이스입니다. 하나의 작업 단위를 정의하여 실행 가능한 코드 조각을 객체 형태로 표현하는데 사용됩니다.
Looper
Looper는 MessageQueue를 관리하는 클래스입니다. Looper는 내부에 하나의 MessageQueue를 갖고 있고, Looper를 통해 MessageQueue에 접근할 수 있습니다.
public final class Looper {
...
final MessageQueue mQueue;
...
}
Looper는 아래와 같이 사용할 수 있습니다.
Thread {
Looper.prepare() // 현재 스레드에 Looper + MessageQueue 생성
val handler = Handler(Looper.myLooper()!!)
handler.post {
Log.d("LooperExample", "커스텀 스레드에서 실행 중")
}
Looper.loop() // 메시지 큐 루프 시작
}.start()
- Looper.prepare()로 Looper와 MessageQueue 생성
- Looper.loop()는 무한 루프에 진입하여 메시지를 계속 처리
- Looper.myLooper()로 현재 스레드의 루퍼를 가져와 핸들러를 생성
위의 예시 코드를 봐서 알 수 있듯이 Looper는 실행의 주체가 아닌, 실행을 관리하는 도구입니다. 작업은 Looper가 연결된 스레드가 실행 주체이고, 작업을 MessageQueue로 보내고 처리하는 역할은 Handler가 합니다.
Handler
Handler는 MessageQueue에 작업을 전달해주는 클래스입니다. 어떤 작업을 나중에 실행하거나, 다른 스레드로 전달할 수도 있습니다.
Handler는 다음과 같은 작업을 진행합니다.
- Runnable 또는 Message를 MessageQueue에 넣는다.
- Looper는 큐를 돌면서 메시지를 꺼낸다.
- Handler가 해당 작업을 받아서 실행한다.
위의 예시의 post로 작업을 MessageQueue에 등록합니다.
handler.post {
println("LooperExample 커스텀 스레드에서 실행 중")
}
Message 객체는 `handleMessage()`를 오버라이드 하여 메시지를 어떻게 처리할지 정의하는 방식으로 사용합니다.
Thread {
Looper.prepare()
val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
1 -> Log.d("Test", "Message 1 도착") // 실행됨
2 -> Log.d("Test", "Message 2 도착")
}
}
}
val message = Message.obtain()
message.what = 1
handler.sendMessage(message)
Looper.loop()
}.start()
Handler를 통해 전달된 작업은 MessageQueue에 등록되고, 해당 Handler가 연결된 Looper가 이를 순차적으로 꺼내어 처리합니다.
작업이 큐에서 꺼내지면, 다시 Handler로 전달되어 `handleMessage()` 혹은 Runnable의 `run()` 메서드가 호출됩니다.
좀 더 구체적인 흐름은 다음과 같습니다:
- 개발자가 Handler.sendMessage() 또는 Handler.post() 등의 메서드를 호출하면,
- 메시지(Message) 또는 작업(Runnable)이 MessageQueue에 등록됩니다.
- 해당 Handler가 바인딩된 Looper가 계속해서 MessageQueue를 루핑(Looping)하며,
- 큐에 들어온 메시지를 순차적으로 꺼내어,
- 해당 메시지를 보낸 Handler의 handleMessage()를 호출하거나, Runnable을 실행(run())합니다.
⚠️ 주의사항
- Handler는 반드시 Looper가 있는 스레드에서 생성되어야 합니다.
- 메인 스레드는 앱 실행 시 자동으로 Looper를 가지고 있으므로 바로 사용 가능
- 커스텀 스레드에서는 Looper.prepare() → Looper.loop() 필요
메인 스레드의 Looper
안드로이드에서의 메인 스레드는 안드로이드 앱에서 모든 UI 작업을 담당하는 스레드입니다. 이 메인 스레드에는 앱 시작과 동시에 자동으로 생성되는 Looper가 존재합니다.
이는 안드로이드 프레임워크의 `ActivityThread` 클래스에서 다음과 같이 초기화됩니다.
public static void main(String[] args) {
// 생략...
Looper.prepareMainLooper(); // 메인 스레드용 Looper 생성
// 생략...
Looper.loop(); // 이벤트 루프 시작
}
개발자가 메인 스레드의 Looper를 사용할 때에는 이렇게 접근합니다.
val mainLooper = Looper.getMainLooper()
val handler = Handler(mainLooper)
handler.post {
// 이 코드는 메인(UI) 스레드에서 실행됨
}
만약 다른 스레드에서 UI를 변경하고 싶다면 메인 스레드의 Looper에 작업을 전달해야 합니다.
// 백그라운드 스레드
Thread {
val result = "완료"
// 메인 스레드로 전달
Handler(Looper.getMainLooper()).post {
textView.text = result
}
}.start()
✅ 마무리 요약
구성 요소 | 역할 |
MessageQueue | 작업 대기열을 관리 |
Looper | 메시지를 꺼내고 실행 요청 전달 (실행 주체 아님) |
Handler | 작업을 큐에 등록하고, 꺼낸 작업을 실행 |
Runnable / Message | 실제 실행할 코드 또는 메시지 데이터 |
이 게시글에서는 안드로이드의 비동기 처리 메커니즘 중 MessageQueue, Looper, Handler가 어떻게 상호작용하는지 살펴보았습니다.
Reference
What's message queue in Android?
Can someone explain what's the message queue in Android? Is it the list of processes running? I can't find a good source explaining it. I am asking because I was reading about the method post of...
stackoverflow.com
MessageQueue and Looper in Android
Most of you are familiar with threads in Java but Android provides one more class HandlerThread derived from Thread. The only significant…
medium.com
'Android > Kotlin' 카테고리의 다른 글
[Flow 연산자] 생산자 총정리 (0) | 2025.03.31 |
---|---|
코루틴의 구조적 동시성(Structured Concurrency) (0) | 2025.03.25 |
[Flow 연산자] 중간 연산자 총정리 (0) | 2025.02.12 |
Flow의 collect은 언제 suspend 될까? (0) | 2025.01.21 |
왜 SharedFlow의 emit()은 suspend 함수일까? (2) | 2025.01.01 |