[Android] Thread, 개념 이해하기

윤석규·2023년 5월 21일
2
post-thumbnail

👀 시작하기 전에...

1. 프로세스(process)란?

프로세스(process)는 단순히 실행 중인 프로그램이라고 할 수 있다.
즉, 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것을 말한다.
프로세스는 프로그램에 사용되는 데이터와 메모리 등의 자원 그리고 스레드(thread)로 구성된다.

2. 스레드(thread)란?

스레드(thread)프로세스(process) 내에서 실제로 작업을 수행하는 주체를 의미한다.
모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행한다.
또한, 두 개 이상의 스레드를 가지는 프로세스를 멀티 스레드 프로세스라고 한다.

🤷 스레드(thread)를 사용하는 이유?

안드로이드의 UI 작업은 메인 스레드에서만 이루어져야 한다. 하지만 만약 서버 통신이나 DB 작업같이 무거운 작업을 메인 스레드에서 작업하게 된다면 UI 작업이 멈추게 되고 그러면 모든 UI 이벤트가 작동하지 않고 애플리케이션이 중단된 것처럼 보이게 된다. 이러한 오류를 방지하기 위해 서버 통신이나, DB 작업과 같은 작업을 하는 워커 스레드가 필요하다.

📌 Looper, Handler 그게 뭔데?

1. Looper란?

하나의 스레드(thread)는 오직 하나의 Looper를 가진다.
LooperMessageQueue를 가지고 있는데, 이 MessageQueue는 해당 스레드가 처리해야하는 동작들이 메시지 형태로 저장된다. 그리고 저장된 메시지를 꺼내서 적절한 Handler로 전달하는 역할을 한다.

메시지(Message)란 무엇일까?

메시지(Message)는 스레드 통신에서 Handler에 데이터를 보내기 위한 클래스이다.
MessageQueue 에는 메시지들이 큐 형태로 저장되어있고, Looper가 메시지들을 차례대로 처리한다.

Message객체는 내용물이 Runnable객체나 Message객체 두 가지 종류로 이루어져있다. Runnable객체는 Handler에 메시지를 전달하지 않고 run()을 통해 Runnable 작업을 바로 시작한다. Message객체는 내부에 명시되어있는 HandlerhandleMessage()를 수행하여 처리한다.

2. Handler란?

Handler는 특정 메시지를 LooperMessageQueue에 추가하거나, 특정 메시지를 꺼내어 전달하면 이를 처리하는 역할을 한다. 쉽게 말하면 LooperMessageQueue의 중간다리 역할을 한다.

메시지를 전달하는 경우

sendMessage() 메서드를 통해 메시지 큐에 Message객체를 전달한다.
post() 메서드를 통해 Runnable객체를 전달한다.

메시지를 전달받는 경우

Runnable객체라면 run() 메서드를 호출해서 작업을 실행한다.
Message 객체라면 handleMessage() 메서드를 호출해서 메시지를 전달받는다.

🌊 동작 흐름 살펴보기

  1. 워커 스레드에서 HanldersendMessage()를 통해 메인 스레드의 LooperMessageQueue에 메시지를 전달한다.
  2. 메인 스레드의 LooperMessageQueue의 메시지 하나를 Handler에 전달한다.
  3. Handler에서 handleMessage()를 통해 메시지를 처리한다.

💻 Thread를 사용해보자

1. Handler

// 메시지를 전달받는 경우
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)

2. Looper

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

profile
나만의 것으로 만들 때까지 공부합니다 ✏️

0개의 댓글