在閱讀該篇文章以前要清楚的一些知識點:html
- 一個線程之中能夠有多個
Handler
,可是每一個線程之中只有一個Looper
和一個MessageQueue
- 消息隊列
MessageQueue
是在Looper
中進行建立的,Handler
的做用是往MessageQueue
中發送消息和處理消息的- 在子線程中若是要建立
Handler
對象,必須先調用Looper.prepare()
方法建立Looper
對象和MessageQueue
- 在什麼線程中建立
Handler
,那麼該Handler
就持有該線程的Looper
和MessageQueue
,例如在主線程中建立Handler
就能夠更新UI界面就是由於這個
Handler容許你發送和處理Message消息,每一個Handler的實例都與一個線程和該線程中的消息隊列(MessageQueue)關聯,當你建立一個新的Handler時,它就綁定到了正在建立它的線程(消息隊列),而後就能夠經過該Handler將Message和runnables發送到該消息隊列,並在消息出來時執行他們。java
Handler有兩個用途:android
往消息隊列中發送消息能夠經過多線程
爲應用程序建立進程時,主線程建立消息隊列,該隊列負責管理頂級應用程序對象(活動,廣播接收器等)及其建立的任何窗口。您能夠建立本身的線程,並經過Handler與主應用程序線程進行通訊。這是經過調用與之前相同的post或sendMessage方法完成的。而後,將在Handler的消息隊列中調度給定的Runnable或Message,並在適當時進行處理。async
官方文檔中屢次提到了MessageQueue這個消息隊列,那麼該消息隊列何時建立的,Handler怎麼發送消息到MessageQueue中的,以及怎麼處理這些消息的?下面經過源碼的方式梳理這個流程.ide
一、建立MessageQueueoop
MessageQueue的建立不須要咱們本身去建立,而是經過建立Looper的時候自動建立的,代碼以下:post
private Looper(boolean quitAllowed) {
//在Looper的構造方法中,建立了MessageQueue
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
複製代碼
因爲該構造方法是私有的,因此提供了靜態方法prepare()
來建立Looper,而後經過myLooper()
方法來獲取Looper對象,這要是爲何咱們在子線程中建立Handler的時候要先調用prepare()
方法的緣由。ui
二、Handler發送消息到MessageQueue中this
經過調用Handler的 post
sendMessage
等方法能夠將消息發送到MessageQueue中,具體中間經歷了什麼,全部的post
方法和sendMessage
方法,最終調用的都是sendMessageAtTime
方法能夠看一下源代碼:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//獲取到消息隊列,消息隊列是在Handler的構造方法中獲取到的
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的時候,構造方法中會獲取當前線程的Looper,而後經過Looper獲取到MessageQueue.
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());
}
}
//獲取該線程的Looper對象,Looper對象是放在ThreadLocal對象中的,保證每一個線程只有一個Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//獲取了消息隊列,在sendMessage和post的最後都是往隊列中插入消息
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
複製代碼
三、處理消息
首先咱們要弄明白是誰來進行處理消息的,咱們通常建立Handler的時候會重寫一個方法handleMessage
, 若是是經過post(Runnable run)
的方法發送的消息,處理是在handleCallback
的方法中,不須要本身去實現。
那麼是何時調用的handleMessage
方法呢?
Looper.loop()
方法開啓死循環,該循環中就是從MessageQueue中取消息來處理,若是沒有消息了會阻塞。釋放CPU資源public static void loop() {
final Looper me = myLooper();
//...省略部分代碼...
//開啓死循環
for (;;) {
//從消息隊列中獲取Message,該方法會阻塞,若是隊列中沒有消息,則阻塞,釋放CPU資源
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//...省略部分代碼...
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
//target就是這個消息是哪個Handler發送的,target就是那個Handler對象,
//調用Handler的dispatchMessage方法來派發消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...省略部分代碼...
//消息回收
msg.recycleUnchecked();
}
}
複製代碼
loop()
方法中找到了消息發送到MessageQueue的時候,Looper會從消息隊列中獲取到消息,而後經過消息中的target
字段獲取到消息所屬的Handler
,而後調用Handler
的dispatchMessage
來進行處理。/** * Handle system messages here. */
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
複製代碼
從上面的方法中能夠看到,若是callback
不爲空,就直接執行handlerCallback
,callback
其實就是一個Runnable
, handleCallback
方法就是調用run())
方法來使其運行。 若是callback
爲空的狀況下就是經過handleMessage
來進行處理消息了。因此咱們在建立了Handler
的時候要重寫該方法進行一些操做
以上基本上就是Handler
的一些流程說明了,如今咱們不多用到Handler
,可是不少線程的切換底層仍是用到的Handler
, 這是基礎。因此仍是須要了解一下。文中也有說明了Looper
Handler
和MessageQueue
之間的關係,還有什麼疑問能夠留言,如看到必定回解答。感謝閱讀🤝