Handler ✇

푸른하늘·2022년 7월 15일
0
post-thumbnail

Android UI 작업은 무!조!권 Main Thread 에서 작업해야 한다.

왜 그럴까?

🍎 Main Thread 와 Worker Thread가 동시에 TextView에 접근할 때

  • 동시에 textView 에 접근하게 된다면 교착상태가 발생할 수 있다
  • MainThread가 일정 시간 멈추면 ANR이 생겨서 앱이 강제종료가 될 수 있다.

🍎 왜 UI 는 싱글 쓰레드 모델로 동작할까?

  • 만약 여러 쓰레드에서 TextView의 텍스를 변경하는 상황이라면 어떤 결과가 나올지 미지수 이기 때문이다.
    - 동작의 무결성을 보장 하기 위해 오로지 Main Thread에서만 UI관련 동작 가능

🍎 이런 문제를 해결 할려면? Handler 등장 !!

Worker Thread에서 Handler를 사용하여 메세지를 전달한다. 전달된 메세지는 Main Thread를 통해 작업을 처리한다.

🍎 Main Thread 에서 무거운 작업을 하지마라

  • UI 작업을 Main Thread 함으로 무거운 작업을 할시에 UI 처리가 늦어져서 느려진다.

🍎 Handler, Message Queue, Looper

  • Handler
    • 특정 메세지를 Looper 의 MessageQue에 넣는다
    • Looper가 MessageQueue 에서 특정 메세지를 꺼내어 전달하면 이를 처리하는 기능을 수행함

다른 스레드에게 메세지를 전달하려면

  • 수신 대상 스레드에서 생성한 핸들러의 post나 sendMessage등의 함수를 사용
  • 수신 대상 스레드의 Message Queue에 message가 저장되기 때문에.

결국 , Thread에서 만든 Handler를 순차적으로 넣어 놓은 것을 다시 빼서 실행 시키는 것이다.

🍏 그래서
Handler1 가 Main Thread 라면 Handler2,Handler3은 다른 작업 쓰레드이다.
Hadndler 2 or 3 에서 UI 작업을 요청하면 Message Queue 에 쌓이고
이를 Looper 가 실제 UI작업을 관리하는 handlerMessage를 통해 MainThread에서 순차적으로 실행 시킨다.
Handler의 생성자에 Looper가 전달되는데 이는 모든 Handler가 동일한 Looper를 이용하게 된다.

🍏 그림 처리 순서
(Handler1, Handler3, Handler2) -> Message Queue -> Looper(FIFO)처리 -> handlerMessage

잠깐 코드 보자

new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        // something..
    }
}, 1000);

위에서 말한대로 Handler 생성자에 Looper를 넣게 된다.
위의 예제는 Delay를 주는 코드이다.

🍎 Handler 주요 함수

  • Handler.sendMessage(Message msg)
    : Message 객체를 message queue에 전달하는 역할

  • Handler.sendEmptyMessage(int wht)
    : Message의 wht 필드를 전달하는 함수

  • post()
    : post()는 Message 객체가 아닌 Runnable 객체를 Message queue에 전달한다.
    ex) Handler.post(new Runnable()) // 위에서 본 코드.

🍎 Work Thread 에서 post()를 요청하면?

new Thread(new Runnable(){
	@Override
    public void run() {
		WHandler whandler;
        whandler = new WHandler();
        whandler.post(new Runnable(){
        	@Override
            public void run() {
            	//여기서의 UI 작업은 안된다.
			}
        }
	}    
}

당연히 안된다. UI작업은 메인스레드에서만 가능하기에.
하고싶다면 메인 스레드에서 해야 한다.

new Thread(new Runnable(){
	@Override
    public void run() {		
	    //	여기서는 UI 작업 불가.
        mainHandler.post(new Runnable(){
        	@Override
            public void run() {
            	//여기서의 UI 작업은 가능.
			}
        }
	}    
}

mainHandler로 UI작업을 진행한다
Work Thread내부에서 Main Thread의 Handler를 통해 Runnable 객체가 전달한다.
메인 스레드의 Looper가 Runnable 객체를 꺼내서 run()을 실행한다

MainThread
Handler mainHandler = new Handler()

Work Thread
mainHandler.post(new Runnable())

Main Thread의 mainHandler를 통해 run()을 실행하는 격이다.

참고자료

profile
Developer-Android-CK

0개의 댓글