Android 中 Handler,Looper,HandlerThread 的關係分析

來源:互聯網
上載者:User

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()系列方法擷取,能節約資源,提高效率。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.