Message
안드로이드 쓰레드에는 크게 main thread, background thread 로 나뉜다.
main은 UI에 해당되는 모든 처리를 담당한다.
background는 이 외의 다른 네트워킹 처리라던가 뭔가 시간이 더 걸리는 것을 처리한다.
일단은 이렇게 개념을 잡았다.
메세지는 그렇다면 무엇에 쓰이는 것일까?
main도 처리할 UI 작업이 많고, back도 처리할 작업이 있는 경우
back이 아무리 처리를 많이하고 빨리한다해도 main이 준비되지 않으면 보이지 않는다.
그만큼 back에서는 다양한 업무를 처리하고 main에게 보낸다.
그러나 main이 일이 너무 많다면, 이러한 back의 작업을 무시하거나 back이 완료된 일을 들고 계속 대기해야하는 경우가 생긴다.
이런 현상이 바로 우리가 흔히 느끼는 '렉'이다.
처리가 느려지고 업무는 계속 쌓이는 현상.
이러한 상황을 피하고자 메세지를 사용한다.
메세지를 사용하는 개념은 이렇다.
우편함을 main에게 주자는 것이다.
이 우편함에 back은 자신이 끝낸 일을 계속 우편함에 메세지 형태로 넣어준다.
main은 자기가 여유가 좀 남을때 우편함에서 메세지를 꺼내 back이 해준 일을 처리하고 다른 일을 보든
back이 남긴 일을 모두 처리하든 하는 것이다.
이렇게 된다면, back도 처리한 일을 들고 대기할 일이 없고 바로 다음일로 넘어가는 효율이 생기며
main도 back의 처리를 기다리거나, 다른 일을 처리하는데 원할하게 작동이 가능한 것이다.
여기서 메세지의 쌓이는 방식이 '큐 Queue' 이다.
그래서 이러한 것을 Message Queue(메세지 큐) 라고 한다.
그리고 이러한 메세지 큐를 사용하여 back이 반복 작업을 무진장 하는 것이 Message Loop(메세지 루프) 이다.
메세지 루프의 구성은 아래와 같다.
Message Loop | |
Thread x1 | Looper x1 (메세지 큐를 관리하는 객체) |
main 스레드는 기본적으로 Looper를 갖는 메세지 루프이다.
(따라서, 메인은 Looper에 의해 업무를 처리하고, Looper는 메세지 큐에 있는 업무를 하나씩 빼오는 것이다.)
back 스레드에서는 이런 메세지 루프를 어떻게 구현할까?
Looper를 구성해주면 된다.
Looper를 만들기 위해서는, HandlerThread 라는 클래스를 사용해야한다.
즉, Message Handler(이하 핸들러 = Handler)를 생성하여 main의 핸들러와 소통을 시키는 것이다.
Message 와 Handler ??
Message 의 구조
메세지는 말이 메세지이지, 사실상은 안드로이드 상에서 처리해야할 작업, '일' 이다.
메세지는 Message 클래스의 인스턴스이며, 많은 속성을 갖고 있는데,
세 가지의 속성이 있다.
1. what | 메세지를 나타내는 사용자의 정의 정수 값 |
2. obj | 메세지와 함께 전달되는 사용자 지정 객체 |
3. target | 메세지를 처리할 핸들러 인스턴스 |
즉, 메세지임을 식별하기위한 what, 식별된 메세지에 알맹이인 obj, 이러한 처리 결과를 소통시켜주는 target이있다.
Handler 의 구조
핸들러는 메세지를 처리하는 대상이자, 메세지를 생성하고 게시하는 인터페이스이다.
메세지를 사용하여 실제 작업(일)을 하려면 맨 먼저 '핸들러 인스턴스'가 필요하다.
메세지는 반드시 Looper에서 게시되고 소비되어야 한다.
Looper가 메세지 객체들의 메세지 우편함을 소유하기 때문이다.
따라서 핸들러는 항상 동료인 Looper의 참조를 갖는다.
핸들러는 하나의 Looper에 연결되며, 메세지는 하나의 핸들러에 연결된다.
Looper는 메세지 큐 전체의 메세지들을 가지고 있다.
여러개의 매세지가 동일한 핸들러를 참조할 수도 있다.
여러 개의 핸들러에 하나의 Looper를 연결할 수도 있다.
핸들러의 메세지들이 다른 핸들러의 메세지들과 나란히 존재가 가능하긴 하다.
핸들러 사용
핸들러는 직접 설정하지 않는다.
메세지는 Handler.obtainMessage() 를 호출하여 생성하는 것이 좋다.
이 함수에 위의 세가지 메세지 속성들을(what, obj, target) 전달한다.
이 함수가 호출된 핸들러 객체를 대상 핸들러로 설정하게 된다.
Handler.obtainMessage()
새로운 메세지 객체의 생성을 피하고자 공유되는 재활용 풀(pool)에서 메세지 객체를 가져다 사용한다.
따라서 매번 새로운 인스턴스를 생성하는 것보다 효율적이게 된다.
이렇게 메세지 객체를 얻게 된다면,
이것의 핸들러로 해당 메세지 객체를 전달하기 위해 sendToTarget() 함수를 호출한다.
이렇게 되면, 핸들러가 해당 메세지 객체를 Looper의 메세지 큐 맨 끝에 넣게되는 것이다.
Handler 사용부분은 생각보다 어렵고 복잡해서 나중에 따로 Handler에 대해 포스팅해야겠다.
'Programming > Android' 카테고리의 다른 글
Broadcast Intent (0) | 2021.08.27 |
---|---|
Retrofit (0) | 2021.08.18 |
JetPack AAC: DataBinding (0) | 2021.08.05 |