前言
Handler 在Android 開發(fā)中是使用頻率非常高的遥巴,所以Android 開發(fā)有必要了解Handler 的機(jī)制蘑辑。下面就個(gè)人理解簡(jiǎn)單介紹一下 Handler 原理,在這里我們
需要了解的類
- Handler
- Looper
- Message
- MessageQueue
- ActivityThread
首先要說Looper
Looper 類看名便知其意梯影,循環(huán)兢哭。看Looper 類源碼一定要注意這段代碼:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
該 ThreadLocal 保存不同線程中的Looper,非常重要返帕。
下面我們?cè)诳碙ooper中的一個(gè) prepare 方法桐玻,先看代碼,代碼如下:
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
在這段代碼中看 sThreadLocal.get() 段代碼荆萤,獲取當(dāng)前線程中Looper 實(shí)例镊靴,寫到這我又看到可下面的異常了,那就讓我們看看這個(gè)異常是什么:Only one Looper may be created per thread, 意思是:每個(gè)線程中只可以創(chuàng)建一個(gè)Looper實(shí)例链韭。然后我們?cè)诳纯催@個(gè)方法的功能偏竟,創(chuàng)建自身線程的 Looper 實(shí)例,并將Looper 保存在ThreadLocal 中敞峭。
在看一下 Looper 中 myLooper() 方法踊谋,代碼如下:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
代碼簡(jiǎn)單,就是獲取所在線程中的Looper 實(shí)例旋讹。
在看一下 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();
}
}
該方法主要是獲取主線程中的Looper 實(shí)例,該方法在 ActivityThread 中main中執(zhí)行(ActivityThread 類是程序的入口)沉迹,即在程序的入口創(chuàng)建一個(gè)主線程的 Looper 實(shí)例睦疫。同時(shí),Looper 中還有 getMainLooper() 方法鞭呕,代碼如下:
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
這段代碼是獲取主線程的 Looper 實(shí)例蛤育。
Looper 有一個(gè)非常重要的方法 loop() ,這個(gè)方法非常重要琅拌,主要是負(fù)責(zé)從 MessageQueue 中取出消息交給 Handler 在該線程中執(zhí)行缨伊,寫到這里,可能會(huì)有些蒙进宝,MessageQueue 在什么時(shí)候被實(shí)例的刻坊,看下面這段代碼就知道了:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在Looper 的一個(gè)構(gòu)造方法中MessageQueue被實(shí)例。
下面就要介紹一下 loop() 方法党晋,不多說谭胚,先看看源碼長(zhǎng)什么樣:
public static void loop() {
//獲取該線程中的Looper 實(shí)例
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取該線程中與Looper 相關(guān)聯(lián)的 MessageQueue 對(duì)象
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
// 從MessageQueue 中取出 Message 徐块,如果沒有信息將會(huì)阻塞到這里
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
final Printer logging = me.mLogging;
final long traceTag = me.mTraceTag;
if (traceTag != 0) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
// 調(diào)用 Handler 將 Message 交個(gè) Handler 處理
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
final long newIdent = Binder.clearCallingIdentity();
msg.recycleUnchecked();
}
}
通過上面的這段代碼,我們可以知道 loop() 方法是如何循環(huán)消息的灾而,上面的帶有些沒有用的就刪掉了胡控,在看的時(shí)候也不需要每行都要讀懂,只要把注釋的部分看懂就行旁趟。
現(xiàn)在看一下 Message
Message 類主要是存儲(chǔ)信息的類昼激,通過 Message 中的一些變量就可以看出,下面我們來看一下 Message 中的一個(gè)變量锡搜。
注意:Message 類實(shí)現(xiàn)了 Parcelable 接口進(jìn)行序列化處理橙困,為 Bundle 中進(jìn)行數(shù)據(jù)傳輸
- Handler target
我們可以主要到這個(gè)在Message 中定義了一個(gè) Handler 變量,如果第一次看代碼可能會(huì)有些不知為何耕餐,那我們?cè)趤砘仡櫼幌?Looper 中剛剛我們提高過的一段代碼:
public static void loop() {
........
for (;;) {
// 從MessageQueue 中取出 Message 凡傅,如果沒有信息將會(huì)阻塞到這里
Message msg = queue.next(); // might block
// 調(diào)用 Handler 將 Message 交個(gè) Handler 處理
msg.target.dispatchMessage(msg);
}
........
}
上面代碼是 loop() 方法,無(wú)關(guān)代碼已經(jīng)刪掉肠缔,通過這兩行代碼可以知道夏跷,在循環(huán)信息的時(shí)候,通過 MessageQuery 中取出 Message 消息明未,然后獲取Message 中與該線程綁定的 Handler槽华,再通過取出的該線程中的Handler 消息。
然后我們看一下 Handler
了解Handler 首先一定要看一下Handler 的構(gòu)造方法亚隅,Handler 的構(gòu)造方法有很多硼莽,在這里,我們只看這個(gè) Handler(Callback callback, boolean async) 構(gòu)造方法煮纵。
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;
}
在這些代碼中讓我關(guān)注的代碼只有兩行懂鸵,mLooper = Looper.myLooper();這行代碼很簡(jiǎn)單,獲取該線程的Looper 實(shí)例行疏。再看看 mQueue = mLooper.mQueue; 看到這行代碼就更清楚了吧匆光,獲取該線程中 Looper 中的 MessageQuery 實(shí)例。
然在看一下 sendMessageAtTime(Message msg, long uptimeMillis) 和 enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 兩個(gè)方法:
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
看到上面這兩個(gè)方法代碼也不多酿联,從代碼中可以看到终息,MessageQueue queue = mQueue;和queue.enqueueMessage(msg, uptimeMillis); 是向 MessageQueue 中添加 Message 消息。下面要重點(diǎn)說一下 msg.target = this; 這行代碼贞让,這行代碼和前面介紹 Message 中變量相關(guān)聯(lián)周崭,這行代碼是讓 Message 持有這個(gè)Handler 實(shí)例,在Looper 循環(huán)消息時(shí)可以獲取到該實(shí)例調(diào)用 Handler 中的 dispatchMessage 方法(下面會(huì)介紹 dispatchMessage)喳张,從而調(diào)用 handleMessage续镇。
那么現(xiàn)在我們就來看一下 Handler 中的 dispatchMessage(Message msg) 方法:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
不用解釋了吧, handleMessage(msg);
最后我們看一下 MessageQueue
在這個(gè)類中我們只看一個(gè)方法 enqueueMessage(Message msg, long when) 方法:
boolean enqueueMessage(Message msg, long when) {
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) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
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.
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;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
這個(gè)方法代碼很多销部,我么刪一些沒用的簡(jiǎn)化一下:
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
if (mQuitting) {
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
這個(gè)方法主要是將 Message 存入到 MessageQueue 中摸航,供Looper 循環(huán)使用制跟。
說了這么多,就會(huì)有人想問酱虎,既然 Looper 是 Handler 的核心雨膨,那么MainLooper 在什么時(shí)候被創(chuàng)建,下面我們?cè)诳匆幌?ActivityThread 類读串,一個(gè) Android 程序的入口就在 ActivityThread 類中聊记,所以,我們要看一下該類中 main 方法中的實(shí)現(xiàn):
public static void main(String[] args) {
......
Looper.prepareMainLooper();
Looper.loop();
......
}
}
可以看到在main 函數(shù)中的兩行代碼創(chuàng)建了 Looper 實(shí)例和啟動(dòng) Looepr 中的loop() 循環(huán)爹土。
總結(jié)
在程序啟動(dòng)時(shí)甥雕,ActivityThread 類中啟動(dòng)應(yīng)用,創(chuàng)建UI Thread 的 Looper胀茵, 在創(chuàng)建 UI Thread Looper 后又創(chuàng)建基于該線程的 MessageQuery 與該線程的Looper 進(jìn)行關(guān)聯(lián),所以在activity 中創(chuàng)建的 Handler 是基于 UI Thread 的挟阻,所以 Looper 和 MessageQuery 早就已經(jīng)創(chuàng)建好了琼娘。