앞 부분에서, 핸들러를 통해 안드로이드 스레드 통신 수행시 필요한 메시지 전달 시스템 구성 요소에 대해 정리했다면!
이 부분은, 안드로이드에서 핸들러를 사용해 스레드 통신을 구현하는 방식에 대해 집중적으로!
1. 메시지 수신 스레드 - Handler 객체 생성 및 handlerMessage() 메서드 오바라이드
(1) 가장 먼저, 메인 스레드에서 수신 메시지를 처리하기 위한 핸들러 객체 생성
Handler handler = new Handler() {
} ;
1) 핸들러는, 생성과 동시에 코드가 실행된 스레드에 연결(bind)됨
- Handler 클래스 생성자에서, 현재 스레드의 루퍼(Looper) 및 메시지 큐(MessageQueue)에 대한 참조를 가지게 됨
-> 이후 단계에서, 메시지 전달 시 이 참조를 사용해 메시지 큐에 메시지 넣음
(2) 헨들러에서 수신한 메시지를 처리하기 위해 handleMessage() 메서드 오버라이드
1) handleMessage()
- 메시지 루프를 통해 메시지 큐로부터 꺼낸 메시지를 처리할 수 있도록, Looper에 의해 실행되는 메서드
- 다른 스레드로부터 전달된 데이터 = msg 인스턴스에 담겨져 있음
일반적으로, 정수 타입인 what 변수의 값에 따라 if or switch 등의 조건문으로 처리
public class MainActivity extends AppCompatActivity {
// 메시지 종류를 식별하기 위해 - what 변수에 전달할 값 = 상수로 정의
private final int MSG_A = 0 ;
private final int MSG_B = 1 ;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_A :
break ;
case MSG_B :
break ;
}
}
} ;
}
2. 메시지 송신 스레드 - 수신 스레드의 핸들러 객체 참조를 통해 메시지 객체 획득
(1) 메시지를 보내는 곳에서 = 앞서 생성한 수신 스레드의 핸들러 객체 참조 획득
- 메인 스레드 - 액티비티의 클래스 변수로 핸들러 객체 선언 -> (송신 스레드에서) 액티비티 참조를 통해 핸들러 객체 참조 가능
- 액티비티 내에서 스레드 생성 -> 핸들러 객체 바로 참조 가능
class NewThread extends Thread {
Handler handler = mHandler ;
@Override
public void run() {
while (true) {
// obtain a message.
Message message = handler.obtainMessage() ;
// fill the message object.
message.what = MSG_A ;
message.arg1 = ... ;
message.arg2 = ... ;
message.obj = ... ;
// send message object.
handler.sendMessage(message) ;
}
}
}
(2) 메시지 객체 획득 - Handler 의 obtainMessage() 메서드 사용
1) obtainMessage() 메서드
- 글로벌 메시지 풀(Global Message Pool)로부터 메시지를 가져옴
- 정적(static)으로 생성된 재사용(recycled) 객체로 관리
- new 키워드로 새로운 Message 인스턴스 생성보다 효율적
2) Message 클래스 내 publiuc 클래스 변수
클래스 변수 | 설명 |
int what | 메시지 종류 식별을 위한 사용자 정의 메시지 코드 |
int arg1 | 메시지를 통해 전달되는 정수의 값 저장 |
int arg2 | 메시지를 통해 전달되는 정수의 값 저장 |
Object obj | 수신 스레드에 전달할 임의의 객체 저장 |
Message replyTo | 해당 메시지에 대한 회신용 메신저 |
int sendingUid | 메시지를 보낸 uid를 가리키는 필드 |
2) 사용하는 필드 종류에 따른 obtainMessage() 메서드의 여러 형태
- Message 객체 획득 시 모든 클래스 변수를 사용해야 하는 것은 X
메서드 프로토타입 | 설명 |
Message obtainMessage() | 메시지의 target이 핸들러 자신으로 지정된 Message 객체 리턴 |
Message obtainMessage(int what) | what이 지정된 Message 객체 리턴 |
Message obtainMessage(int what, int arg1, int arg2) | what, arg1, arg2가 지정된 Message 객체 리턴 |
Message obtainMessage(int what, Object obj) | what, obj가 지정된 Message 객체 리턴 |
Message obtainMessage(int what, int arg1, int arg2, Object obj) | what, arg1, arg2, obj가 지정된 Message 객체 리턴 |
3. 메시지 보내기
(1) Handler.sendMessage() - 메시지 객체를 수신 스레드에 전송
1) obtainMessage() 메서드로 획득한 메시지 객체에 보내고자 하는 데이터를 채운 후
-> 메시지 객체를 수신 스레드에 전송
handler.sendMessage(message);
2) 다양한 프로토타입의 sendMessage()
- 파라미터, 메시지를 보내는 시점, 메시지 큐 내의 위치 등에 따라 다양한 프로토타입 존재
- 메서드 중 AtTime, Delayed, AtFrontOfQueue 등의 접미사가 붙은 메서드 : 메시지 처리 시점 조절
-> 메시지 큐 안에서, 메시지 처리 우선순위 or 스레드 실행 대기 시간 등에 영향 O
-> 각 메서드의 정확한 동작 방식에 따라 사용 주의 필요
메서드 프로토타입 | 설명 |
boolean sendEmptyMessage(int what) | Message 클래스 변수 중 what 멤버만 채워진 Message 객체 전달 |
boolean sendEmptyMessageAtTime(int what, long uptimeMillis) | uptimeMillis에 지정된 시각에, what 멤버만 채워진 Message 객체 전달 |
boolean sendEmptyMessageDelayd(int what, long delayMillis) | 현재 시각에서 delayMillis 만큼의 시간 후에, what 멤버만 채워진 Message 객체 전달 |
booleand sendMessage(Message msg) | Message 객체 전달 - 메시지 큐의 가장 마지막에 msg 추가 |
boolean sendMessageAtFrontOfQueue(Message msg) | Message 객체 전달 - 메시지 큐의 가장 처음 위치에 msg 추가 |
boolean sendMessageAtTime(Message msg, long uptimeMillis) | uptimeMillis에 지정된 시각에, Message 객체 전달 |
boolead sendMessageDelayd(Mesage msg, long delayMillis) | 현재 시각에서 delayMillis 만큼의 시간 후에 Message 객체 전달 |
(2) Handler.post()
- Runnable 객체를 보낼 때 사용하는 post() 메서드
- 상황에 따라 sendMessage() 보다 훨씬 간단하게 스레드 통신 수행 가능
- 참고 : https://recipes4dev.tistory.com/170
핸들러 관련 참고 사항
1. 스레드 통신의 대상 = 자기 자신 포함
- 스레드 통신을 위해 핸들러 사용 시, 다른 스레드에서만 메시지를 보낼 수 있다 => X
-> 스레드 통신 대상 = 자기 자신 포함
Ex1) 외부 스레드에서 전달되는 메시지 처리를 위해 구현한 기능 그대로 사용
Ex2) 순차적으로 실행되어야 하는 코드 사이에, 시스템 이벤트가 고려되어야 하는 상황 등
2. 스레드 당 핸들러 생성 가능 개수
- 핸들러는 여러 개 만들 수 있다!
-> 하나의 핸들러에서 모든 메시지를 처리하는 것 보다,
메시지의 종류 및 기능에 따라 여러 개의 핸들러로 나누어서 처리하는 것이 나음
- 메시지를 보내는 스레드에서 적절한 핸들러 선택해 메시지를 보낼 필요 O
private final Handler mNetworkHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO : process network message.
}
} ;
private final Handler mDeviceHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO : process device message.
}
} ;
참고
- https://recipes4dev.tistory.com/166https://recipes4dev.tistory.com/166
'Mobile > Android' 카테고리의 다른 글
[Android] 안드로이드 Activity 생명주기(Life Cycle) (0) | 2022.04.08 |
---|---|
[Android] 안드로이드 Fragment 생명주기 (0) | 2022.04.08 |
[Android] 안드로이드 브로드캐스트 리시버(Broadcast Receiver) 예제 (0) | 2022.04.04 |
[Android] 안드로이드 4대 컴포넌트 (0) | 2022.04.04 |
[Android] Thread / Handler / Message (0) | 2022.04.01 |