Handler源碼的閱讀主要圍繞Lopper這個對象和這個對象中的Message隊列這兩個東西子刮。
Message
在Android的Handler中窑睁,會通過在子線程發(fā)送Message消息回到主線程并將數(shù)據(jù)更新到主線程的UI葵孤。而這個過程首先從sendMessage這個方法入手沙郭。
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
這里會調用 sendMessageDelayed 方法病线,這個方法會帶有一個延時發(fā)送的性質鲤嫡。
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
繼續(xù)跟蹤
public boolean sendMessageAtTime(@NonNull 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);
}
跟蹤到 sendMessageAtTime 這個方法可以看到 enqueueMessage 這個方法并返回一個布爾值暖眼。
進入到這個方法里
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//將Handler自身放入Message對象中
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
這里調用了queue的enqueueMessage方法诫肠,繼續(xù)追蹤。
boolean enqueueMessage(Message msg, long when) {
//這里的target是發(fā)送消息Handler自身
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
//部分代碼省略...
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//將消息放入隊列之中,并進行排序
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
//當隊列沒有數(shù)據(jù)蛤铜,將消息放入隊列鏈表頭部
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
//判斷消息優(yōu)先級
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//將消息插入鏈表中围肥,并將next指向下一個message
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
//部分代碼省略...
}
return true;
}
可以看到穆刻,這里主要就是將Message對象放入到隊列之中蛹批,而之前那個延時發(fā)送篮愉,在這里就會通過判斷 when 來插入到隊列之中试躏,改變消息隊列發(fā)送順序颠蕴。這也是為什么隊列是一個鏈表結構的原因助析。
Looper
上面的 Message 隊列只看到了將消息放入隊列之中外冀,并沒有看到 handlerMessage() 方法的調用雪隧,而 handlerMessage 則跟Lopper有關脑沿。
之前在項目中马僻,用到 Handler 時韭邓,有想到過能不能通過 Handler 方式來讓子線程發(fā)送消息給主線程女淑。而研究的結果是可以的诗力,但是要調用 Looper.prepareLooper() 和 Looper.loop()這兩個方法凰浮。而這兩個方法就是Handler發(fā)送消息回調handlerMessage()的關鍵。
在 ActvitiyThread 類的main()方法中瓣窄,會調用 Looper.prepareMainLooper() 和 Looper.loop() 這兩個方法俺夕。
public static void main(String[] args) {
//...代碼省略
//生成主線程的looper
Looper.prepareMainLooper();
//...代碼省略
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper.prepareMainLooper()
先追蹤Looper.prepareMainLooper()這個方法
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
上面這段代碼可以看到調用了 prepare(false) 和 myLooper() 來那個個方法姨谷,下面那個方法看名字就能知道是獲取了 Looper 對象梦湘。
先看prepare(false) 這個方法捌议。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//生成looper對象哼拔,并放入主線程的ThreadLocal對象中
//此處的set方法就是ThreadLocal獲取當前線程并保存和將對象保存到ThreadLocal中的方式
//set方法中會通過當前線程去ThreadLocalMap中拿到線程的數(shù)據(jù)信息
sThreadLocal.set(new Looper(quitAllowed));
}
可以看到 sThreadLocal.set(new Looper(quitAllowed)) 這段,這段代碼做了兩件事情:
生成 Looper 對象瓣颅,并放入主線程的 ThreadLocal 對象中
ThreadLocal獲取當前線程并將線程和 Lopper 對象保存到 ThreadLocalMap 中
這里的set方法倦逐,會將生成的 Looper 對象放入到 ThreadLocalMap 中,這個Map的Key為當前的線程對象宫补,Value 為 Lopper 對象檬姥。
而myLooper()方法就是從ThreadLocalMap中獲取Looper對象。
public static @Nullable Looper myLooper() {
//通過ThreadLocal獲取到當前線程的looper對象
//如果是主線程守谓,則在ActivityThread的main()方法中已經聲明了looper對象的生成
return sThreadLocal.get();
}
Looper.loop();
接下來看 Looper.loop() 方法穿铆。
public static void loop() {
//拿到當前線程的looper對象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取looper對象中保存的隊列
final MessageQueue queue = me.mQueue;
//...省略代碼
//無線循環(huán)隊列
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//...省略代碼
try {
//調用Handler的dispatchMessage方法
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...省略代碼
//回收此次的Message對象,之后申請Message對象時可以重復使用
msg.recycleUnchecked();
}
}
而上面這段代碼就能看到通過 myLooper() 方法拿到 Looper 對象您单,并且通過 Looper 對象拿到隊列斋荞。然后無線循環(huán)從這個對象拿出消息虐秦,最后調用 Handler 的 dispatchMessage(msg) 方法。
這個在主線程無線循環(huán)不會卡死手機的原因就在它是在 ActvitiyThread 類的main()方法中幸逆,并且是最后執(zhí)行的一個方法。這樣其實也可以理解為正因為這個無線循環(huán),我們的APP才會一直執(zhí)行,直到用戶關閉APP踏揣。
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
而dispatchMessage方法里就會調用handleMessage括享,也就是回調Handler handleMessage方法剩愧。
這樣犬第,Handler整個流程就走完了。