1. 程式人生 > >【原創】源碼角度分析Android的消息機制系列(六)——Handler的工作原理

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

urn long empty isa pat stat 開啟 it is performed

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

先看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的工作原理