프로세스(process)
는 단순히 실행 중인 프로그램이라고 할 수 있다.
즉, 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것을 말한다.
프로세스는 프로그램에 사용되는 데이터와 메모리 등의 자원 그리고 스레드(thread)
로 구성된다.
스레드(thread)
는 프로세스(process)
내에서 실제로 작업을 수행하는 주체를 의미한다.
모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행한다.
또한, 두 개 이상의 스레드를 가지는 프로세스를 멀티 스레드 프로세스라고 한다.
안드로이드의 UI 작업은 메인 스레드에서만 이루어져야 한다. 하지만 만약 서버 통신이나 DB 작업같이 무거운 작업을 메인 스레드에서 작업하게 된다면 UI 작업이 멈추게 되고 그러면 모든 UI 이벤트가 작동하지 않고 애플리케이션이 중단된 것처럼 보이게 된다. 이러한 오류를 방지하기 위해 서버 통신이나, DB 작업과 같은 작업을 하는 워커 스레드가 필요하다.
하나의 스레드(thread)
는 오직 하나의 Looper
를 가진다.
Looper
는 MessageQueue
를 가지고 있는데, 이 MessageQueue
는 해당 스레드가 처리해야하는 동작들이 메시지 형태로 저장된다. 그리고 저장된 메시지를 꺼내서 적절한 Handler
로 전달하는 역할을 한다.
메시지(Message)
는 스레드 통신에서 Handler
에 데이터를 보내기 위한 클래스이다.
MessageQueue
에는 메시지들이 큐 형태로 저장되어있고, Looper
가 메시지들을 차례대로 처리한다.
Message
객체는 내용물이 Runnable
객체나 Message
객체 두 가지 종류로 이루어져있다. Runnable
객체는 Handler
에 메시지를 전달하지 않고 run()
을 통해 Runnable
작업을 바로 시작한다. Message
객체는 내부에 명시되어있는 Handler
의 handleMessage()
를 수행하여 처리한다.
Handler
는 특정 메시지를 Looper
의 MessageQueue
에 추가하거나, 특정 메시지를 꺼내어 전달하면 이를 처리하는 역할을 한다. 쉽게 말하면 Looper
와 MessageQueue
의 중간다리 역할을 한다.
sendMessage()
메서드를 통해 메시지 큐에 Message
객체를 전달한다.
post()
메서드를 통해 Runnable
객체를 전달한다.
Runnable
객체라면 run()
메서드를 호출해서 작업을 실행한다.
Message
객체라면 handleMessage()
메서드를 호출해서 메시지를 전달받는다.
Hanlder
의 sendMessage()
를 통해 메인 스레드의 Looper
의 MessageQueue
에 메시지를 전달한다.Looper
는 MessageQueue
의 메시지 하나를 Handler
에 전달한다.Handler
에서 handleMessage()
를 통해 메시지를 처리한다.// 메시지를 전달받는 경우
class MyHandler : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
// 다른 Thread에서 받아온 message 처리 구문 작성
}
}
// 메시지를 전달하는 경우
val handler = Handler()
handler.post {
// 해당 handler와 연결된 thread에 전달할 runnable 객체 내부 코드 작성
}
// 해당 handler와 연결된 thread에 message 객체 전달
handler.sendMessage(message)
class MainActivity : AppCompatActivity() {
private lateinit var handler: Handler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myThread = Thread {
Looper.prepare() // Looper 준비
handler = Handler() // myThread의 handler 생성
Looper.loop() // Looper 시작(동작)
}
myThread.start() // myThread 시작
}
override fun onDestroy() {
super.onDestroy()
handler.looper.quit() // Looper 종료
// handler.looper.quitSafely() - MessageQueue의 모든 작업 수행 후 Looper 종료
}
}
위와 같이 수동으로 Looper
객체를 생성하는 번거로움을 피하기 위해, 안드로이드에서는 Thread
를 상속한 Handler
클래스인 HandlerThread
클래스를 제공한다. HandlerThread
는 내부에서 Looper.prepare()
, Looper.loop()
를 수행해준다.
class MainActivity : AppCompatActivity() {
private lateinit var handlerThread: HandlerThread
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handlerThread = HandlerThread("thread_name")
handlerThread.start() // HandlerThread 시작 및 looper 시작
}
override fun onDestroy() {
super.onDestroy()
handlerThread.quit() // HandlerThread looper 종료
}
}
참고한 블로그
https://velog.io/@haero_kim/Android-Looper-Handler-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90
https://jungwoon.github.io/android/2019/09/25/Handler-Looper.html
https://hungseong.tistory.com/26