【原創】源碼角度分析Android的消息機制系列(六)——Handler的工作原理
ι 版權聲明:本文為博主原創文章,未經博主允許不得轉載。
先看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, booleanasync) { 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的工作原理