Android 中 Handler,Looper,HandlerThread 的關係分析
最近項目中要用到 HandlerThread,對其的用法一直不甚瞭解,趁著五一放假就花了點時間研究一下,順便備份在部落格上。
因為剛開始研究的是 HandlerThread,所以我們就從 HandlerThread 入手,我們先來看一下它的原始碼
/* * Copyright (C) 2006 The Android Open Source Project */package android.os;/** * Handy class for starting a new thread that has a looper. The looper can then be * used to create handler classes. Note that start() must still be called. */public class HandlerThread extends Thread { int mPriority;//線程優先順序 int mTid = -1;//TID Looper mLooper;//Looper成員變數 public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT;//建構函式,設定預設線程優先順序 } /** * Constructs a HandlerThread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority;//建構函式,根據參數設定線程優先順序 } /** * Call back method that can be explicitly over ridden if needed to execute some * setup before Looper loops. */ protected void onLooperPrepared() {//主要提供給子類,讓子類去重寫 } public void run() {//run方法,終點來了 mTid = Process.myTid();//擷取TID Looper.prepare();//後面在Looper類裡看 synchronized (this) {//同步 mLooper = Looper.myLooper();//後面在Looper類裡看 notifyAll();//通知所有線程 } Process.setThreadPriority(mPriority);//設定線程優先順序 onLooperPrepared();//HandlerThread類裡沒有實現,子類可以實現,做一些預先處理操作 Looper.loop();//後面在Looper類裡看 mTid = -1; } /** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @return The looper. */ public Looper getLooper() { if (!isAlive()) {//如果線程死掉了,返回null return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) {//如果線程活著,但是為null,就一直等待,與run方法裡面的synchronized相一致 try { wait(); } catch (InterruptedException e) { } } } return mLooper;//返回Looper成員變數 } /** * Ask the currently running looper to quit. If the thread has not * been started or has finished (that is if {@link #getLooper} returns * null), then false is returned. Otherwise the looper is asked to * quit and true is returned. */ public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit();//後面在Looper類裡看 return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() {//返回TID return mTid; }}
原始碼不是很多,有些涉及到Looper類裡面的方法,我們再來看一下Looper類的原始碼(只分析涉及到的方法和成員變數)。
/* * Copyright (C) 2006 The Android Open Source Project */package android.os;import android.util.Log;import android.util.Printer;import android.util.PrefixPrinter;public class Looper { private static final String TAG = "Looper"; // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); final MessageQueue mQueue; final Thread mThread; volatile boolean mRun; private Printer mLogging = null; private static Looper mMainLooper = null; // guarded by Looper.class /** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper());//把和當前線程相關的Looer變數(參考Looper構造方法)放進sThreadLocal中 } /** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { Looper me = myLooper();//擷取和當前線程相關的Looper變數 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } MessageQueue queue = me.mQueue;//和當前線程相關的Looper變數的MessageQueue // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); while (true) {//死迴圈喲 Message msg = queue.next(); // might block,擷取Message if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } long wallStart = 0; long threadStart = 0; // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); wallStart = SystemClock.currentTimeMicro(); threadStart = SystemClock.currentThreadTimeMicro(); } msg.target.dispatchMessage(msg);//這一句最關鍵,Message的Target是什嗎?沒錯,是Handler,下面我們就來看一下Handler類 if (logging != null) { long wallTime = SystemClock.currentTimeMicro() - wallStart; long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); if (logging instanceof Profiler) { ((Profiler) logging).profile(msg, wallStart, wallTime, threadStart, threadTime); } } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycle();//回收利用Message,所以以後我們使用Message的時候,多使用obtain方法。 } } } /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static Looper myLooper() { return sThreadLocal.get(); } /** * Return the {@link MessageQueue} object associated with the current * thread. This must be called from a thread running a Looper, or a * NullPointerException will be thrown. */ public static MessageQueue myQueue() { return myLooper().mQueue; } private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); } public void quit() { Message msg = Message.obtain(); // NOTE: By enqueueing directly into the message queue, the // message is left with a null target. This is how we know it is // a quit message. mQueue.enqueueMessage(msg, 0); }}
我們來看一下Handler類的原始碼
/* * Copyright (C) 2006 The Android Open Source Project */package android.os;import android.util.Log;import android.util.Printer;import java.lang.reflect.Modifier;/** * A Handler allows you to send and process {@link Message} and Runnable * objects associated with a thread's {@link MessageQueue}. Each Handler * instance is associated with a single thread and that thread's message * queue. When you create a new Handler, it is bound to the thread * message queue of the thread that is creating it -- from that point on, * it will deliver messages and runnables to that message queue and execute * them as they come out of the message queue. * /public class Handler { private static final boolean FIND_POTENTIAL_LEAKS = false; private static final String TAG = "Handler"; /** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. */ public interface Callback { public boolean handleMessage(Message msg); } /** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { } /** * Handle system messages here. */ public void dispatchMessage(Message msg) {//重要,在Lopper.loop()方法裡面裡調用的就是這個方法 if (msg.callback != null) { handleCallback(msg);//msg的callBack成員變數是Runnable類型,這裡執行的是msg.callback.run(),但是我們一般不給Message的callback成員變數賦值。 } else { if (mCallback != null) {//如果我們給new()的Handler類的Callback類型的成員變數賦值,就往下面執行,但是我們一般不這麼做。 if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//我們一般在這做我們想要的操作,這個方法需要我們繼承Handler類後重寫。 } } /** * Default constructor associates this handler with the queue for the * current thread. * * If there isn't one, this handler won't be able to receive messages. */ public Handler() { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = null; } /** * Constructor associates this handler with the queue for the * current thread and takes a callback interface in which you can handle * messages. */ public Handler(Callback callback) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; } public final Message obtainMessage() { return Message.obtain(this);//擷取msg,最後調用的msg的obtain()方法,最後msg的target就是this,也就是調用者Handler } /** * Use the provided queue instead of the default one. */ public Handler(Looper looper) { mLooper = looper; mQueue = looper.mQueue; mCallback = null; } /** * Use the provided queue instead of the default one and take a callback * interface in which to handle messages. */ public Handler(Looper looper, Callback callback) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; } // if we can get rid of this method, the handler need not remember its loop // we could instead export a getMessageQueue() method... public final Looper getLooper() { return mLooper; } private final void handleCallback(Message message) { message.callback.run(); } final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; IMessenger mMessenger;}
Looper類和Handler類的原始碼不完整,只是分析了和HandlerThread相關的成員變數和方法。
經過我們的一步步分析,現在思路就清晰了:
1. 當HandlerThread運行到Looper.loop()的時候,一直死迴圈。通過msg.target.dispatchMessage(msg)方法讓msg的target(當通過Handler的obtainMessage()系列方法擷取msg的時候,msg的target就是該handler)也就是Handler去通過它的handleMessage(msg)方法去處理msg。
2. 但是msg是那裡來的?通過看原始碼我們發現是通過當前線程的Looper的MessageQueue類型的變數mQueue.next()方法得到的。
3. Handler也有一個MessageQueue類型的變數,那麼,Handler的MessageQueue變數怎麼和Looper類的MessageQueue類型變數有關係嗎?
4. 記不記得Handler類有一個構造方法叫public Handler(Looper) ? 對了,就是這個構造方法讓他們產生了關係。( HandlerThread有一個Looper類型的變數,通過getLooper()方法能擷取,傳入到Handler類的構造方法,這樣,Handler就和HandlerThread聯絡起來了)。
5. 以至於最後HandlerThread操作的是和Handler同一個MessageQueue。
6. Handler可以通過sendMessage(msg)系列方法把msg放到MessageQueue,然後HandlerThread把msg從MessageQueue裡面取出來,然後調用Handler的handleMessage(msg)方法處理。
通俗的總結一下運行時的流程:Handler把Message放到MessageQueue,HandlerThread不停的從MessageQueue裡拿出來Message,然後調用Handler的HandleMessage(Message)方法不停的處理Message。
經過分析,我們來寫一個demo測試一下,有訊息佇列的線程(非主線程):
工程如下
HandlerThread分析Demo
下面是我測試結果:
結果表示:HandlerThread確實維護了一個訊息佇列,從Log中可以看出他們的TID都是一樣的。
總結:
1. HandlerThread維護了一個訊息佇列,這樣我們不用到處建立對象。但是它一直在後台運行(死迴圈),從這個方面講,它還是很耗資源的
2. Message其實有一套緩衝+迴圈利用機制,以後用到Message的地方都用obtain()系列方法擷取,能節約資源,提高效率。