先舉個子線程中使用Handler的例子:
package com.haoran.myhandler;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
Looper looper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(){
@Override
public void run() {
System.out.println("子線程中打印線程名:"+Thread.currentThread().getName());
Looper.prepare();
looper = Looper.myLooper();
looper.loop();
}
}.start();
Handler handler = new Handler(looper){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("主線程中打印線程名:"+Thread.currentThread().getName());
}
};
Message message = Message.obtain();
handler.sendMessage(message);
}
}
大家看了這段代碼估計會有疑惑,子線程中怎麼沒有new Looper()? Handler(looper)的構造做了什麼操作?
那好,我們debug運行下
其實
從 FrameWork層 MainActivity.class –> Activity.class –> ActivityThread.class –> ActivityThread.class中的內部類(H.class) 和main方法。
Handler消息機制起了很大的作用,從四大組件的啓動,模板模式進行生命週期方法的回調,都是消息機制在默默的進行着。從源碼層看,安卓主線程在創建過程中,在ActivityManager的main入口,通過自動初始化了一個Looper和Handler以及handleMessage方法進行消息機制 再通過H.class中進行四大組件的消息機制的判斷
消息類型定義:
消息處理方法:
我們說了半天的Handler消息機制的重要性好像和Handler消息機制原理沒有半毛錢關係,最開始代碼引發我們思考的問題依然無法回答。
下面我們從Handler消息機制的UML圖,及相關類源碼進一步進行分析,先上圖:
這張架構圖我們可以花時間分型一下,分析他們之間互相持有的關係。哈哈,這裏我就簡單概述一下,再走一下源碼。。。
首先
作爲一個合格的助手,Handler裏有mQueue和mLooper對象;於是就有了消息隊列MessageQueue和輪詢器Looper,再將消息Message放在消息隊列裏面。Message記錄着相對應的Handler,MessageQueue裏持有Message對象,Looper通過持有的MessageQueue對象,對消息進行輪詢讀寫
圖解:
上圖的代碼大家應該看着不舒服,我把源碼截取一點,一起走一遍,不過我們要帶着問題走:
1. 消息怎麼被髮送到消息隊列中的?
2. 消息怎麼被Handler/Looper處理的?
3. Handler 對象是怎麼創建出來的?
4. loop 這個方法什麼時候執行?
5. Message 、Handler 、 Looper、 MessageQueue 、 Thread、 ThreadLocal直接的關係是什麼呢?
我們知道,
handler.sendMessage(Messagemessage)或handler.postRunnable(Runnable runnable);
都是可以發送消息的,其實post底層也是封裝了sendMessage方法的,所以我們從handler.sendMessage(Message msg)開始吧 –>go
Mainactivity中 handler.sendMessage(message)
Message message = Message.obtain();
handler.sendMessage(message);
點進去 –>Handle.class的sendMessage方法
繼續 –> sendMessageDelayed方法
繼續 –> sendMessageAtTime方法
這裏發現mQueue,按谷歌工程師開發習慣mQueue是Handler.class類裏面的成員變量。那麼,mQueue是在什麼時候被賦值的呢?
我們找一找 –> 發現Handler(Callback callback, boolean async)構造
Handler的其他構造裏,同樣賦值操作是Looper給的,那麼mLooper是如何賦值的呢?
可以通過handler構造外界傳遞一個,通常我們用無參構造。哈哈,我們的例子裏傳遞了一個looper哦,大家還記得嗎?
上圖裏 mLooper = Looper.myLooper();
那麼Looper裏的myLooper()方法做了什麼操作呢?點點點! –>
??sThreadLocal 又是什麼啊?這裏留個坑,一會兒填,咱們先刻舟求劍
好了,先回到 sendMessageAtTime方法發現,走了自己的enqueueMessage();方法,–>Handler.class 的enqueueMessage()
發現 –>
走到了MessageQueue.class 的enqueueMessage(Message msg, long when) 方法
這個方法有點長用僞代碼解釋一下吧
if (p == null || when == 0 || when < p.when) {
// 當前發送的message需要馬上被處理調,needWake喚醒狀態置true
} else {
// 當前發送的message被排隊到其他message的後面,needWake喚醒狀態置false
}
.....
// 是否喚醒主線程
if (needWake) {
nativeWake(mPtr);
}
MessageQueue.enqueueMessage()執行,會往消息隊列裏添加Message。消息隊列MessageQueue按照時間對所有的Message進行排序。
往消息隊裏裏添加Message分爲兩種情況
1.當前發送的Message位於隊列頭部。需要馬上處理消息。就會把當前的喚醒狀態needWake喚醒狀態置爲true,喚醒主線程,讓輪循器取消息。
2.當前發送的Message被排隊排到了其他Message的後面。就不需要喚醒主線程了。就會把當前的喚醒狀態needWake置爲false。不喚醒主線程。
等等,哈哈,我們的Handler.class中enqueueMessage方法還沒有分析完畢,細心的同學會發現 – >
msg.target = this;
這做了什麼操作?
//1. Message的target標記爲當前發送的Handler
//2. Looper取到message根據target把message分發給相應的Handler
至此,我們把Handler的發送,MessageQueue的給消息排隊解釋完畢了,接下來就是Looper中如何輪詢獲取消息,並交給Handler處理的
看Looper.class –> 核心Looper.loop()輪循
while (true) {//死循環,輪循取消息
// 取消息,如果沒有消息,就阻塞
Message msg = queue.next(); // might block //有可能會阻塞。
...
//取消息。取到消息就發送給Handler
msg.target.dispatchMessage(msg);
...
}
queue.next()方法
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
msg.target.dispatchMessage(msg)也就是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);
}
}
dispatchMessage: 先判斷 Message 對象上的 callback 是否爲空,
如果不爲空,執行 callback 上的 run 方法(聯想到了handler.postRunnable方法了嗎?)
如果爲空,讓 handler 去處理消息,判斷 handler 上的 mCallback 是否爲空
①如果 mCallback 不爲空,讓 mCallback.handleMessage 方法來處理消息
②如果 mCallback 爲空,纔會調用 handler.handleMessage 方法來處理消息
哈哈,差不多了,還記得我們留的一個坑嗎ThreadLocal看源碼吧:)
很像一個map集合啊,就當是一個hashmap集合吧,我們android中把 K設置爲thread名,V設置爲looper吧
get方法 :
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
set方法 :
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
哈哈,再見了,不足的地方咱們一起學習吧