【原創】源碼角度分析Android的訊息機制系列(六)——Handler的工作原理

來源:互聯網
上載者:User

標籤:color   文章   構造方法   leak   lis   find   接收   拋出異常   處理   

ι 著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

 

先看Handler的定義:

/** * 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. *  * <p>There are two main uses for a Handler: (1) to schedule messages and * runnables to be executed as some point in the future; and (2) to enqueue * an action to be performed on a different thread than your own. * ………. * */public class Handler {……..}

由源碼中對Handler的定義以及注釋,我們可知,Handler主要就是用來發送和處理訊息的。每一個Handler的執行個體都和一個線程以及該線程的MessageQueue相關聯。Hadnler主要有2個作用:①在未來某個時刻去發送或處理Message或Runnable(post方法)②在另一個線程中去處理訊息(send方法)。

 

再看Handler的構造方法:

public Handler() {        this(null, false);    }…….public Handler(Callback callback, boolean async) {        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;        mAsynchronous = async;    } ……

由構造方法可知,當前線程中沒有Looper時,若建立Handler對象,則會拋出"Can‘t create handler inside thread that has not called Looper.prepare()"異常。所以,必須要在有Looper的線程中建立Handler,否則,程式將拋出異常。

 

Handler的工作主要包含訊息的發送和接收過程。訊息的發送可以通過post的一系列方法以及send的一系列方法來實現。下面來看一系列post方法:

   public final boolean post(Runnable r)    {       return  sendMessageDelayed(getPostMessage(r), 0);    }    public final boolean postAtTime(Runnable r, long uptimeMillis)    {        return sendMessageAtTime(getPostMessage(r), uptimeMillis);    }    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)    {        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);    }    public final boolean postDelayed(Runnable r, long delayMillis)    {        return sendMessageDelayed(getPostMessage(r), delayMillis);    }    public final boolean postAtFrontOfQueue(Runnable r)    {        return sendMessageAtFrontOfQueue(getPostMessage(r));    }

通過源碼,我們可以知道,post的一系列方法最終還是通過send的一系列方法來實現的。

 

下面看send的一系列發送訊息的源碼:

    public final boolean sendMessage(Message msg)    {        return sendMessageDelayed(msg, 0);    }    public final boolean sendEmptyMessage(int what)    {        return sendEmptyMessageDelayed(what, 0);    }    public final boolean sendMessageDelayed(Message msg, long delayMillis)    {        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {        MessageQueue queue = mQueue;        if (queue == null) {            RuntimeException e = new RuntimeException(                    this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);            return false;        }        return enqueueMessage(queue, msg, uptimeMillis);    }

由源碼可知,Handler發送訊息的過程,其實就是向訊息佇列中插入了一條訊息。

由MessageQueue的工作原理和Looper的工作原理我們可以知道,當MessageQueue中插入了新的訊息後,next方法就會返回該訊息給Looper,Looper接收到訊息並開始處理訊息,但最終Looper是通過調用Handler的dispatchMessage方法來處理訊息的,即訊息最終還是交給了Handler去處理。

 

下面來看Handler的dispatchMessage方法的源碼,如下:

 public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }    private static void handleCallback(Message message) {        message.callback.run();    }

首先,判斷了Message的callback是否為null,若不為null,則調用handleCallback方法。

Message中有屬性:  /*package*/ Runnable callback;  那麼,message.callback即Handler的post方法所傳遞的Runnable參數。再結合handleCallback方法的源碼可知,handleCallback方法其實就是開啟了一個子線程,去處理post方法。

再看dispatchMessage方法的源碼,若Message的callback為空白,則判斷mCallback是否為null,由Handler的源碼:

final Callback mCallback;    public interface Callback {        public boolean handleMessage(Message msg);    }    /**     * Subclasses must implement this to receive messages.     */    public void handleMessage(Message msg) {    }

可知,Callback就是一個介面,而且其中定義了handleMessage方法。由此我們可以聯想到,當需要擷取一個Handler執行個體時,我們除了可以繼承Handler,重寫handleMessage方法外,我們還可以通過實現Callback 介面,然後實現介面中的handleMessage方法來實現。

接著來看dispatchMessage方法的源碼,若mCallback為null,最後還是調用handleMessage方法來處理訊息。

在開發過程中,當用Handler處理訊息時,我們一般是需要重寫handleMessage方法的,處理訊息的邏輯由我們自己來寫。

 

 

【原創】源碼角度分析Android的訊息機制系列(六)——Handler的工作原理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.