본문 바로가기

Mobile/Android

[Android] 안드로이드 핸들러(Handler)

앞 부분에서, 핸들러를 통해 안드로이드 스레드 통신 수행시 필요한 메시지 전달 시스템 구성 요소에 대해 정리했다면!

 

이 부분은, 안드로이드에서 핸들러를 사용해 스레드 통신을 구현하는 방식에 대해 집중적으로!

 

핸들러를 통한 스레드 통신 수행 절차

 

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