系列目錄: Handler機制原理
1.prepareMainLooper()
//Looper#prepareMainLooper
public static void prepareMainLooper() {
// 設(shè)置不允許退出的Looper
prepare(false);
synchronized (Looper.class) {
//將當前的Looper保存為Looper诽里。每個線程只允許執(zhí)行一次
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
2.prepare()
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//Looper#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));
}
boolean quitAllowed
表示Looper是否允許退出尚胞,true就表示允許退出缸逃,對于false則表示Looper不允許退出
sThreadLocal
的作用已在之前文章中做過解析,異步ThreadLocal
3. Looper()
//Looper#Looper
private Looper(boolean quitAllowed) {
// 創(chuàng)建MessageQueue對象
mQueue = new MessageQueue(quitAllowed);
// 記錄當前線程
mThread = Thread.currentThread();
}
4. myLooper()
//Looper#myLooper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
sThreadLocal.get()是和prepare(boolean)方法里面的sThreadLocal.set(new Looper(quitAllowed))一一對應(yīng)的炉爆。
5. loop()
//Looper#loop
public static void loop() {
// 獲取TLS存儲的Looper對象
final Looper me = myLooper();
//沒有Looper 對象榜配,直接拋異常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取當前Looper對應(yīng)的消息隊列
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
// 確保權(quán)限檢查基于本地進程,而不是基于最初調(diào)用進程
final long ident = Binder.clearCallingIdentity();
// 進入 loop的主循環(huán)方法
// 一個死循環(huán)盖袭,不停的處理消息隊列中的消息,消息的獲取是通過MessageQueue的next()方法實現(xiàn)
for (;;) {
// 可能會阻塞
Message msg = queue.next(); // might block
// 如果沒有消息彼宠,則退出循環(huán)
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
// 默認為null鳄虱,可通過setMessageLogging()方法來指定輸出,用于debug功能
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// 用于分發(fā)消息兵志,調(diào)用Message的target變量(也就是Handler了)的dispatchMessage方法來處理消息
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
// 確保分發(fā)過程中identity不會損壞
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
// 打印identiy改變的log醇蝴,在分發(fā)消息過程中是不希望身份被改變
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
// 將Message放入消息池
msg.recycleUnchecked();
}
}
loop進入循環(huán)模式宣肚,不斷重復(fù)下面的操作
- 讀取MessageQueue的下一條Message
- 把Message分發(fā)給相應(yīng)的target
- 再把分發(fā)后的Message回到消息池想罕,以便重復(fù)利用
6. quit()
//Looper#quit
public void quit() {
mQueue.quit(false);
}
退出循環(huán)
將終止(loop()方法)而不處理消息隊列中的任何更多消息
7. quitSafely()
//Looper#quitSafely
public void quitSafely() {
mQueue.quit(true);
}
處理完MessageQueue內(nèi)當前的Messager列表后退出循環(huán)