我們先看下面例子
簡單的Looper創(chuàng)建以及Handler的初始化如下:
Looper.prepare();
Handler mhandler = new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
int what = msg.what;
switch (what) {
case 0:
//do.
break;
//case others
default:
break;
}
}
};
Looper.loop();
mhandler.sendEmptyMessage(0);
1.初始化Looper:Looper.prepare()
2.初始化Handler
3.開啟消息隊(duì)列Looper.loop()
4.發(fā)送一個簡單消息:mhandler.sendEmptyMessage(0);
下面我們將追蹤每一步并分析其實(shí)現(xiàn)原理
1.創(chuàng)建Looper
Looper.prepare:
這個方法每個線程只能執(zhí)行一次欣喧,這是怎么實(shí)現(xiàn)的呢?
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
以上代碼可以看出來荒给,prepare方法里面拋出一個異常倦炒,而sThreadLocal.get()又是什么呢显沈,看下他的定義:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
原來是ThreadLoacl, 這是個Java什么類?我個人理解為是線程局部變量逢唤,好比為每個線程創(chuàng)建自己的變量拉讯,線程之間互不影響,這個類主要是起到線程隔離鳖藕,就好比為每個線程都準(zhǔn)備一個變量魔慷,這個變量類型就是<>里面的泛型
那么sThreadLocal就是為每個線程維護(hù)自己的Looper,哪個線程調(diào)用sThreadLocal.get()方法就是得到是自己的<Looper>著恩,這樣以上代碼便是以下意思:
調(diào)用sThreadLocal.get(),如果這個線程有了Looper院尔,那么提示已經(jīng)創(chuàng)建過Looper了,不可能重復(fù)創(chuàng)建喉誊,如果沒有Looper邀摆,那么我可以使用 sThreadLocal.set(new Looper(quitAllowed))
讓sThreadLocal來給當(dāng)前線程維護(hù)一個Looper,這就保證了線程里面Looper的唯一性
那么Looper初始化做了哪些事情了呢裹驰?
new Looper():
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
構(gòu)造函數(shù)里面只創(chuàng)建了一個MessageQueue和引用當(dāng)前線程隧熙,這就準(zhǔn)備好了Looper,那么MessageQueue是什么呢幻林,如其名贞盯,是一個消息隊(duì)列音念,我們經(jīng)常聽到消息隊(duì)列,消息隊(duì)列又是什么躏敢,其實(shí)就是一個隊(duì)列闷愤,可以執(zhí)行入隊(duì)出隊(duì),其實(shí)就是將一個Message放入這個隊(duì)列件余,需要的時候在隊(duì)列最前面拿出最前面的一個Message讥脐,作為一個IT gay大伙都知道
2.初始化Handler
2.1Handler構(gòu)造函數(shù):
new Handler([Looper]):
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
參數(shù)1:Looper引用
參數(shù)2:回調(diào)接口,handlerMessage或者自己實(shí)現(xiàn)Handler內(nèi)部方法handlerMessage啼器,兩者都可以
參數(shù)3:可能是關(guān)于消息是否需要同步的標(biāo)志位
3.開啟隊(duì)列消息
Looper.loop()
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
以上是loop的內(nèi)部幾段重要實(shí)現(xiàn)
首先拿到消息隊(duì)列旬渠,然后開始執(zhí)行for死循環(huán),調(diào)用queue.next()方法取出里面Message端壳,如果消息是空告丢,那么循環(huán)結(jié)束,否則執(zhí)行msg.target.dispatchMessage损谦,而dispatchMessage就是調(diào)用的Handler的handleMessage岖免,那么消息的處理Handler便實(shí)現(xiàn)了。然后重置msg內(nèi)部所有元素[注意在此之后引用的msg內(nèi)部元素都是初始化的了照捡,如果handleMessage中調(diào)用runOnUiThread取final類型的msg颅湘,那么runOnUiThread拿到的msg元素都是重置過的],下面就是追蹤如何向隊(duì)列MessageQueue里面放入消息和queue.next()到底怎么取出消息的
先看queue.next()如何實(shí)現(xiàn)
Message next(){
for (;;) {
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;
}
}}}
}
摘取了一些關(guān)鍵代碼,next()方法是取消息隊(duì)列里面的Message的栗精,有2種情況闯参,第一種隊(duì)列里面沒有消息,那么是一個死循環(huán)术羔,方法沒有任何返回赢赊,第二種是隊(duì)列里面有Message,那么會取出!isAsynchronous()的msg级历,這就是上面Handler初始化構(gòu)造函數(shù)第三個參數(shù)來影響取出的msg,說明此時只會取異步的msg并返回叭披,我們接著看下面的判斷寥殖,判斷當(dāng)前時間和消息時間差,如果當(dāng)前時間小于msg.when(消息需要出隊(duì)的時間)涩蜘,那么不做任何操作嚼贡,等待下一次循環(huán)判斷時間是否滿足,這里我們可以猜測handler.postDelayed是不是就是給Msg預(yù)設(shè)一個出隊(duì)時間同诫,如果當(dāng)前時間大于msg.when(消息需要出隊(duì)的時間)粤策,那么返回當(dāng)前msg,并且將mMessages隊(duì)列鏈表指向消息的下一個误窖,即下一個消息就是隊(duì)列頭叮盘,之前的msg都會被彈出并且消費(fèi)掉秩贰,這便是消息隊(duì)列的next()取出方法
4.發(fā)送消息:
mhandler.sendEmptyMessage(0)分析:
sendEmptyMessageDelayed(what, 0);
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
Message.obtain返回一個Message對象
方法追蹤到低就是執(zhí)行的是enqueueMessage方法,這個方法就是向MessageQueue里面放入Message柔吼,如下:
boolean enqueueMessage(Message msg, long when) {
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);
}
}
}
上面摘取的代碼可以看出毒费,這是一個隊(duì)列的排序,按照when每個消息的時間進(jìn)行排序愈魏,將每個消息按照時間最近越靠前來重新排序觅玻,或者說是將新的Message插入到一個時間由進(jìn)到遠(yuǎn)已經(jīng)排序好的隊(duì)列中,變量mMessage是隊(duì)列頭培漏,里面next指向下一個Message溪厘,這就形成了一個隊(duì)列鏈表,隊(duì)列里面每個元素有一個指針指向下一個元素牌柄,這就是Handler的sendMessage安排一個消息到消息隊(duì)列里面畸悬,等待Looper的彈出并處理該消息
總結(jié):
1.初始化Looper準(zhǔn)備MessageQueue,[ThreadLocal的運(yùn)用]
2.初始化Handler,引用MessageQueue與Thread
3.Looper.loop啟動循環(huán)友鼻,不停查找MessageQueue隊(duì)列里面消息并取出最近消息進(jìn)行消費(fèi)傻昙,回調(diào)handleMessage
4.Handler.sendMessage將生成的Message關(guān)聯(lián)Handler并且按時間排序插入MessageQueue隊(duì)列中,等待loop循環(huán)取出