Handler機(jī)制詳解
Handler運(yùn)行機(jī)制梳理
我們?cè)谑褂肏andler的時(shí)候痒谴,往往是這樣一個(gè)使用步驟:
初始化一個(gè)Handler對(duì)象,重寫(xiě)其handleMessage方法
獲取一個(gè)Message對(duì)象妻怎,并相應(yīng)的為其what羔飞、obj屬性賦值
調(diào)用Handler.sendMessage(msg)方法發(fā)送消息
發(fā)送出來(lái)的消息希柿,將在Handler的handleMessage方法中進(jìn)行處理
因此哭尝,我們從sendMessage方法看Handler執(zhí)行了什么邏輯:
frameworks\base\core\java\android\os\Handler.java
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
……
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)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
由代碼可知斥杜,sendMessage和sendMessageDelayed實(shí)際上都是調(diào)用了sendMessageAtTime方法涕俗。
若是采用sendMessage方法發(fā)送的消息,則uptimeMillis的值=當(dāng)前時(shí)間椎眯;
若采用sendMessageAtTime方法發(fā)送消息挠将,則uptimeMillis的值=當(dāng)前時(shí)間 + delayMillis。
注意“msg.target = this;”這行代碼盅视,this在這里指的自然是發(fā)送這個(gè)Message的Handler對(duì)象,這行代碼非常重要
最終旦万,我們是通過(guò)“queue.enqueueMessage(msg, uptimeMillis);”這行代碼將Message塞入了一個(gè)MessageQueue對(duì)象中闹击,我們看看這個(gè)方法又做了什么:
frameworks\base\core\java\android\os\MessageQueue.java
final boolean enqueueMessage(Message msg, long when) {
……
synchronized (this) {
……
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
……
return true;
}
以上代碼只做了一件事,將我們的Message加入到MessageQueue中,并根據(jù)when這個(gè)時(shí)間值對(duì)我們的MessageQueue中的Message進(jìn)行了排序成艘。
這個(gè)when值赏半,就是之前我們傳進(jìn)來(lái)的那個(gè)uptimeMillis。
那么淆两,消息被放到了我們的MessageQueue中断箫,又由誰(shuí)來(lái)取出并分發(fā)呢?
答案是我們的Looper秋冰。
我們的應(yīng)用程序啟動(dòng)仲义,主線程開(kāi)啟時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)Looper,并調(diào)用其loop方法埃撵,使其開(kāi)始輪詢(xún)MessageQueue中的消息:
frameworks\base\core\java\android\app\ ActivityThread.java
public static final void main(String[] args) {
……
Looper.prepareMainLooper();
……
Looper.loop();
……
}
frameworks\base\core\java\android\os\Looper.java
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
……
}
……
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
……
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
……
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
return;
}
……
msg.target.dispatchMessage(msg);
……
}
}
}
Loop方法實(shí)際上是維持著一個(gè)死循環(huán)赵颅,他不停的從MessageQueue中取到Message并將Message分發(fā)。
當(dāng)MessageQueue中沒(méi)有消息時(shí)暂刘,Loop會(huì)處于阻塞狀態(tài):
Message msg = queue.next(); // might block
Message被分發(fā)的代碼為:
msg.target.dispatchMessage(msg);
這里的msg.target饺谬,即發(fā)送我們這個(gè)Message的Handler對(duì)象,因此谣拣,這行代碼還是調(diào)用回了我們的Handler的dispatchMessage方法:
frameworks\base\core\java\android\os\Handler.java
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
代碼可知募寨,我們通過(guò)Handler發(fā)送的消息,最終由我們Handler的handleMessage方法來(lái)進(jìn)行處理森缠,Handler的這一套運(yùn)行機(jī)制到此完畢拔鹰。
Handler機(jī)制靠什么保證消息不混亂
假如現(xiàn)在我們new了幾個(gè)Handler,同時(shí)去sendMessage辅鲸,我們?nèi)绾伪WC哪個(gè)Handler發(fā)送的消息格郁,就交由哪個(gè)Handler的handleMessage方法去處理?
牢記我們發(fā)送消息和分發(fā)消息的時(shí)候的這2行代碼:
frameworks\base\core\java\android\os\Handler.java
public boolean sendMessageAtTime(Message msg, long uptimeMillis){
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
……
return sent;
}
frameworks\base\core\java\android\os\Looper.java
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
return;
}
……
msg.target.dispatchMessage(msg);
……
}
}
}
通過(guò)這個(gè)“msg.target”独悴,我們就可以保證:哪個(gè)Handler發(fā)送的消息例书,哪個(gè)Handler來(lái)處理。
ThreadLocal
ThreadLocal就是線程局部變量刻炒,經(jīng)常使用此方法保存線程內(nèi)的共享變量决采。
同一個(gè)線程內(nèi)的多個(gè)不同的類(lèi),可以通過(guò)ThreadLocal來(lái)共享全局變量坟奥。
當(dāng)線程結(jié)束后树瞭,對(duì)應(yīng)該線程的局部變量將自動(dòng)被垃圾回收,所以顯式調(diào)用該方法清除線程的局部變量并不是必須的操作爱谁。
所有在主線程new出來(lái)的Handler晒喷,最后都是通過(guò)ThreadLocal取用主線程創(chuàng)建的那個(gè)Looper,來(lái)實(shí)現(xiàn)的消息分發(fā)访敌。
Handler機(jī)制中凉敲,我們通過(guò)ThreadLocal來(lái)保證一個(gè)線程中只有一個(gè)Looper。
Looper會(huì)阻塞主線程么
Looper是不會(huì)阻塞主線程的寺旺,正因?yàn)橛蠰ooper這個(gè)死循環(huán)爷抓,我們的app才能去即時(shí)的相應(yīng)用戶(hù)的操作。
不止是我們自己通過(guò)代碼邏輯發(fā)送的Message阻塑,包括我們應(yīng)用中所有的操作蓝撇,比如開(kāi)啟一個(gè)Activity,調(diào)用Activity生命周期的方法:onCreate\onResume等陈莽,都是通過(guò)Handler發(fā)送消息渤昌,由Looper輪訓(xùn)到來(lái)處理的虽抄。
因此,Looper不會(huì)有阻塞我們的主線程耘沼。