Handler機(jī)制的問題
相信很多人都遇到過這樣的面試題。
那為什么需要Handler呢,你們有反問過自己 || 面試官嗎?
看完這篇文章相信你下次去面試就能好好的刷一下面試官的氣焰了(裝逼),畢竟很多公司本身沒有Android開發(fā)人員,面試題都是網(wǎng)上找的,或者理解不深。
為什么要有Handler
從源碼角度理解該機(jī)制
本文為樓主原創(chuàng),轉(zhuǎn)載請表明出處:http://blog.csdn.net/Suma_sun/article/details/51427312
Handler的由來
- 首先為什么需要Handler呢? ——更新UI控件只能在UI線程,其他線程得使用Handler機(jī)制傳遞小弟到主線程。
- 那為什么只能在UI線程更新UI呢?——因?yàn)锳ndroid是單線程模型
- 那為什么Android是單線程模型?
多線程并發(fā)訪問UI可能導(dǎo)致UI控件處于不可預(yù)期的狀態(tài)。如果加鎖加鎖,雖然能解決。但是缺點(diǎn)明顯:1. 鎖機(jī)制讓UI訪問邏輯變得復(fù)雜;2. 加鎖導(dǎo)致效率低下
Handler機(jī)制
Handler機(jī)制有幾個(gè)核心類:Handler、Looper、Message、MessageQueue。
Handler機(jī)制是一個(gè)典型的生產(chǎn)者消費(fèi)者模式——多個(gè)生產(chǎn)者,一個(gè)消費(fèi)者,該模式是處理線程安全的一個(gè)經(jīng)典模式,如果不了解的請自行查閱相關(guān)資料,不懂也沒關(guān)系,并不影響接下來的內(nèi)容。
關(guān)聯(lián)Looper
首先我們常用的構(gòu)造方法
/**
* Default constructor associates this handler with the {@link Looper} for the current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
默認(rèn)的構(gòu)造器 new Handler() 會(huì)從當(dāng)前線程獲取Looper關(guān)聯(lián)。
如何關(guān)聯(lián)呢?
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
下面這個(gè)構(gòu)造是所有傳入null Looper的歸屬
//默認(rèn)不開啟
private static final boolean FIND_POTENTIAL_LEAKS = false;
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
//當(dāng)子類是匿名類 或者 是成員類 或者 本地類時(shí)
//并且不是靜態(tài)類時(shí)進(jìn)行打印
//獲取該類的修飾符 & 靜態(tài)修飾符常量,&位運(yùn)算,將值轉(zhuǎn)為二進(jìn)制進(jìn)行對位比較,當(dāng)某一位都為1時(shí)該位結(jié)果為1,只要某位有一個(gè)為0時(shí)結(jié)果位為0
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());
}
//用于警告開發(fā)者該類可能存在泄漏
}
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;
}
mLooper = Looper.myLooper();//關(guān)聯(lián)Looper關(guān)鍵代碼
//Return the Looper object associated with the current thread. Returns null if the calling thread is not associated with a Looper.
意思是返回當(dāng)前線程的Looper對象,如果為空告知線程關(guān)聯(lián)Looper
所以當(dāng)我們在Activity中創(chuàng)建Handler沒問題,而在子線程中創(chuàng)建會(huì)報(bào)錯(cuò)的原因就在這里
獲取消息
在Looper中有一函數(shù)loop();該函數(shù)會(huì)一直輪循獲取消息,直到?jīng)]有消息返回退出。
//......
for (;;) {
//......
Message msg = queue.next(); // might block
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
......
}
在MessageQueue中找到next()方法
Message next() {
//......
for(;;){
//......
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 (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
}
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
//......
}
該方法也是一個(gè)輪循,并且是帶同步塊的操作,直到返回Message,或者調(diào)用quit(boolean safe)方法 改變mQuitting 使其返回null。
//Looper
public void quit() {
mQueue.quit(false);
}
處理消息
獲取到Message后會(huì)調(diào)用其持有的Handler對象dispatchMessage(msg)方法
msg.target.dispatchMessage(msg);
Message中找到如下代碼
Handler target;
Runnable callback;
Handler
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler收到消息后,先判斷消息內(nèi)的回調(diào)Runnable是否為空//post(Runnable)等方法
,為空就調(diào)用Handler內(nèi)部的Runnable,
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
然后調(diào)用handleMessage(msg);
public interface Callback {
public boolean handleMessage(Message msg);
}
上面已經(jīng)就這源碼關(guān)鍵代碼梳理了一遍,部分代碼并不全面,請各位自行查看源碼,這樣更加深刻。