Handler

나고수·2022년 5월 8일
0

1일1공부

목록 보기
38/67

Handler?

  • 안드로이드의 메인쓰레드는 UI쓰레드 라고도 불리며, 이름처럼 UI 변경에 관련된 일을 처리한다.
    따라서, 처리 시간이 오래걸리는 일을 메인쓰레드에서 처리하면 ANR(Android Not Responding) 에러가 나면서 앱이 crash난다.
  • 그러면 오래걸리는 일은 어디서 처리를 해줘야할까?
  • Main쓰레드와 연결된 handler를 통해 처리해줘야한다.
    (물론 workerThread1, workerThread2끼리 연결해 줄 수도 있겠지만, 일단 가장 자주 쓰이는 메인쓰레드 핸들러 위주로 설명하겠다.)

상황 : Worker Thread 에서 Main Thread로 처리하고 싶은 작업을 보낸다.

  1. 수신받는 쓰레드(여기서는 메인쓰레드)의 Handler(Loop.getMainLoop())를 이용해 Message/Runnable 객체를 보낸다.
Handler(Looper.getMainLoop()).post()
Handler(Looper.getMainLoop()).sendMessage()
  1. Handler를 통해 보내진 Message/Runnable은 수신받는 쓰레드의 Message Queue에 FIFO구조로 정렬된다.
  2. 수신받는 쓰레드의 Looper가 Message Queue에 있는 작업들을 핸들러에 전달한다.(looper가 속한 쓰레드의 Message Queue의 작업들을 순서대로 핸들러에 전달하는 일을 계속 반복해서 한다고 해서 이름이 looper이다.)
  3. Handler가 작업을 전달받으면 handleMessage() 함수를 통해 작업을 처리한다.

중요 포인트

수신받는 쓰레드의 핸들러를 이용해서 message/Runnalbe을 전달해야 한다.

  • 이유 : 그림에서 보듯이, 수신받는 쓰레드 내부에 그 쓰레드의 handler, Looper, Message queue가 있기 때문에.

Handler()이 deprecated된 이유 & 대체방법

  • When you create a new Handler it is bound to a Looper.(Handler는 Looper에 바인딩된다.)
    즉, Handler와 Looper은 한세트처럼 만들어져야하는데, Looper없이 Handler를 만들거나 하는 경우가 있어서 오류가 나더라.
Handler(Looper.getMainLooper())
Handler(Looper.myLooper())

처럼 Looper을 명확히 지정해줘야한다.

Looper란?

  • Class used to run a message loop for a thread. (쓰레드를 위하여 message queue에 있는 message/runnable 객체를 FIFO 방식으로 handler에 가져다주는 일을 반복-loop-하는 클래스)
  • Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
    (MainThread 말고, 개발자가 직접 만드는 Thread에는 기본적으로 Looper가 없다. 따라서 아래와 같이 prepare & loop 함수로 looper를 만들어줘야한다.)
  class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare(); //looper 준비

          mHandler = new Handler(Looper.myLooper()) {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop(); 
          //stop 될때까지-외부 쓰레드에서 이 쓰레드의 looper.quit()을 해주기 전까지- 
          //meesage queue에 message/runnable이 있으면 hnalder에 전달하는 일을 계속해라!
      }
  }

HandlerThread

  • A Thread that has a Looper. 일반 쓰레드와 다르게 기본적으로 Looper를 가지고 있는 쓰레드.
  • getLooper ()로 Thread에 해당하는 looper를 불러올 수 있다.

Message란?

  • Defines a message containing a description and arbitrary data object that can be sent to a Handler. (설명이나 데이터 등을 담아서 Handler에 보낼 수 있는 객체)
        Handler(Looper.getMainLooper()).sendMessage(Message.obtain())
        //Int 데이터를 포함하여 Runnable 콜백이나 Any 객체 등 여러 데이터를 담아 보낼 수 있다. 
        //what은 수신자가 이 메시지의 내용을 식별할 수 있도록 사용자 정의 메시지 코드. 
        //각 핸들러에는 메시지 코드에 대한 고유한 이름 공간이 있으므로 다른 핸들러와 충돌하는 것에 대해 걱정할 필요가 없다.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val mainHandler = MyHandler()
        val message = mainHandler.obtainMessage(100) //메인쓰레드에 message 보내기 
        mainHandler.sendMessage(message)
    }

    inner class MyHandler : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) { 
        //looper로 부터 message를 받은 후 어떻게 처리할지 구현 
        //main 쓰레드의 handler 이기 때문에 여기서 ui 변경처리를 해줘야 한다. 
            super.handleMessage(msg)
            findViewById<TextView>(R.id.tv).text = msg.what.toString()
        }
    }
}

시점을 정해서 message/runnable 처리하기

참고블로그1
참고블로그2
공식문서

profile
되고싶다

0개의 댓글