English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
서론
前几天看到一道面试题:Thread、Handler和HandlerThread有什么区别?这个题目有点意思,对于很多人来说,可能对Thread和Handler很熟悉,主要涉及到Android的消息机制(Handler、Message、Looper、MessageQueue),详见《从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)》
하지만 이 HandlerThread는 무엇을 위해 사용되는 것인가요? Handler 또는 Thread 인가요? 우리는 Handler가 UI를 비동기적으로 업데이트하는 데 사용된다고 알고 있습니다. 더 구체적으로는 스레드 간의 통신을 위해 사용된다고 말할 수 있습니다. UI를 업데이트할 때는 서브 스레드와 UI 메인 스레드 간의 통신입니다. 그런 다음 우리가 서브 스레드와 서브 스레드 간의 통신을 원한다면 어떻게 해야 할까요? 물론 결국 Handler를 사용하는 것입니다.+Thread를 사용하여 완료하는 것이 좋지 않습니다.(Looper를 직접操作해야 합니다), Google 공식은 매우 조용히 우리를 위해 HandlerThread라는 클래스를 포장해 주었습니다. 바로 이전에 말한 것입니다: HandlerThread.(다중 스레드 시나리오에 대한 유사한 포장은 AsyncTask와 같습니다)
사용 방법
그래서 HandlerThread의 사용 방법을 먼저 보겠습니다:
먼저 HandlerThread를 생성하고 start()를 실행합니다.
private HandlerThread mHandlerThread; ...... mHandlerThread = new HandlerThread("HandlerThread"); handlerThread.start();
Handler를 생성하고 mHandlerThread.getLooper()를 사용하여 Looper를 생성합니다:
final Handler handler = new Handler(mHandlerThread.getLooper()){ @Override public void handleMessage(Message msg) { System.out.println("메시지를 받았습니다"); } };
그런 다음 메시지를 보내기 위해 새로운 서브 스레드를 생성합니다:
new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000);//시간이 걸리는 작업을 모의합니다 handler.sendEmptyMessage(0); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();
마지막으로 onDestroy에서 해제하지 않도록 합니다. 메모리 누수를 피하기 위해서:
@Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); }
실행 결과는 매우 간단합니다. 컨솔에 문자열을 출력하는 것입니다: 메시지를 받았습니다
원리
전체 사용 과정에서 Handler와 관련된 것들에 대해 우리는 걱정할 필요가 없습니다. 메시지를 보내고 메시지를 처리하면 됩니다. Looper와 관련된 것들은 자동으로 처리하게 합니다. 그래서 소스 코드를 보고 어떻게 구현되는지 확인해 보겠습니다. 먼저 생성자를 보겠습니다:
public class HandlerThread extends Thread {}
HandlerThread은 여전히 스레드입니다, 일반 스레드와 어떻게 다릅니다?
public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } ...... }
답은 하나 더 추가된 Looper입니다, 이는 자식 스레드에서만 있는 Looper로, 메시지를 꺼내고 처리하는 데 사용됩니다. HandlerThread 스레드의 run 메서드를 보겠습니다:
protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper();//Looper 생성 notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared();//비어 있는 메서드, Looper가 생성된 후 호출할 수 있으며, 자신의 로직을 재정의할 수 있습니다 Looper.loop();//MessageQueue에서 메시지를 꺼내어 Handler에 처리하는 무한 루프 mTid = -1; }
주로 Looper 작업을 수행하는 것으로, 우리가 직접 Handler를 사용할 때+Thread을 통해 이 작업을 수행해야 할 경우, getLooper() 메서드를 보겠습니다:
public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; }
메서드는 매우 간단합니다. 동기 락을 추가했습니다. isAlive()이 true로 반환되었지만 mLooper가 비어 있으면 계속 기다립니다. 마지막으로 quit 메서드를 보면, 두 가지가 주목할 만합니다:
public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; }
quitSafely는 메시지 큐에 메시지가 남아 있거나 지연된 메시지가 처리되지 않은 경우에 사용되며, 이 메서드를 호출하면 모두 중지됩니다.
결론
HandlerThread 사용 방법은 매우 간단하지만, 이해해야 할 점이 있습니다. 메시지를 처리하는线程이 있다면, 자신의 Looper를 가져야 합니다. Handler가 어디서 생성되었는지에 따라 메시지를 처리할 수 있는 것이 아닙니다.
HandlerThread을 사용하지 않으면,Looper.prepare()와 Looper.loop()와 같은 메서드를 수동으로 호출해야 합니다.
Thread, Handler 및 HandlerThread 관계에 대한 자료 정리는 이렇게 끝납니다. 앞으로도 관련 자료를 계속 추가할 것입니다. 감사합니다.
언급: 이 문서의 내용은 인터넷에서 가져온 것이며, 원작자의 소유물입니다. 이 내용은 인터넷 사용자가 자발적으로 기여하고 업로드한 것이며, 이 사이트는 소유권을 가지지 않으며, 인공 편집 처리를 하지 않았으며, 이에 대한 법적 책임도 부담하지 않습니다. 저작권 문제가 의심되는 내용이 있다면, 이메일을 notice#w로 보내 주세요.3codebox.com에 신고할 때, #을 @으로 변경하여 이메일을 보내고, 관련 증거를 제공하십시오. 실제로 확인되면, 이 사이트는 즉시 의심스러운 저작권 내용을 삭제할 것입니다.