Handler是Android中引入的一種讓開發(fā)者參與處理線程中消息循環(huán)的機(jī)制蹭秋。我們在使用Handler的時候與Message打交道最多,Message是Hanlder機(jī)制向開發(fā)人員暴露出來的相關(guān)類骨望,可以通過Message類完成大部分操作Handler的功能。
說Handler之前先看看Looper谒所。
MessageQueue 是存放Message的消息隊列徙菠,只是一個容器,而Looper 則是讓MessageQueue循環(huán)動起來凝果。
默認(rèn)下創(chuàng)建一個線程祝迂,線程里面是沒有消息隊列的,如果想用消息隊列MessageQueue器净,就需要通過Looper進(jìn)行綁定型雳。下面是一個簡單的例子:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
可以看見Thread通過Looper.prepare() 和 Looper.loop()兩個靜態(tài)方法運(yùn)行。
從源碼里看 Looper的構(gòu)造函數(shù)是private山害,則說明Looper不能再外部實(shí)例化纠俭。就可以猜測到Looper和Thread是一一對應(yīng)的。
private Looper(boolean quitAllowed) {
//實(shí)例化MessageQueue浪慌。
mQueue = new MessageQueue(quitAllowed);
//獲取當(dāng)前線程柑晒。
mThread = Thread.currentThread();
}
看一下Looper.prepare()方法:
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
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));
}
在Looper.prepare() 時候?qū)ooper存起來,存在一個叫ThreadLocal<Looper> 里面眷射。獲取的時候也是通過sThreadLocal.get() 來獲取匙赞。上面提過Message和Thread是一一對應(yīng)的佛掖,也就是說一個線程只能擁有一個Looper,所以在prepare時候先通過sThreadLocal.get()來獲取Looper涌庭,如果是線程剛進(jìn)來那是沒有Looper的所以返回的是null芥被,接著把改Looper存起來。如果有存在則拋出"Only one Looper may be created per thread".
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
Looper.prepare()調(diào)用完之后Looper就準(zhǔn)備好了坐榆,接著就可以通過Looper.loop() 讓MessageQueue循環(huán)動起來拴魄。loop()的源碼:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取當(dāng)前線程的MessageQueue。
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();
final long ident = Binder.clearCallingIdentity();
for (;;) {
//獲取MessageQuene消息隊列的消息.
Message msg = queue.next(); // might block
//如果消息隊列沒有消息席镀,則return匹中,即阻塞在這里,等待獲取Message豪诲。
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 是一個Handler顶捷,這個意思是讓改Message關(guān)聯(lián)的Handler通過dispatchMessage()處理Message。
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.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
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);
}
msg.recycleUnchecked();
}
}
Handler 構(gòu)造函數(shù)
Handler 是暴露給外部調(diào)用者使用屎篱,Handler有多個構(gòu)造函數(shù).
public Handler()
public Handler(Callback callback)
public Handler(Looper looper)
-
public Handler(Looper looper, Callback callback)
?
第1,2個構(gòu)造函數(shù)是沒有傳Looper的服赎,他將獲取該線程的Looper和MessageQueue消息隊列.
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;
}
第3,4構(gòu)造函數(shù)有傳Looper,這兩個構(gòu)造函數(shù)會將該Looper保存到名為mLooper的成員字段中
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
第2,4構(gòu)造函數(shù)還傳入一個Callback回調(diào)函數(shù).是一個接口
public interface Callback {
public boolean handleMessage(Message msg);
}
Handler.Callback是用來處理Message的一種手段交播,在構(gòu)造函數(shù)中傳遞Callback重虑,則可以處理Message,如果返回的是true秦士,則不再往下執(zhí)行缺厉,起到攔截的效果。如果構(gòu)造函數(shù)沒有傳遞Callback隧土,則應(yīng)在Handler中重寫handleMessage方法提针。
sendMessage 發(fā)送消息
在線程中可以通過sendMessage XXX方式往消息隊列中添加Message。
- sendMessage(Message msg):
- sendMessageDelayed(Message msg, long delayMillis):
- sendMessageAtTime(Message msg, long uptimeMillis) :
- sendEmptyMessage(int what)
- sendEmptyMessageDelayed(int what, long delayMillis)
- sendEmptyMessageAtTime(int what, long uptimeMillis) :
通過看Handler源碼可以知道次洼,最終都是調(diào)用sendMessageAtTime方法关贵。而在sendMessageAtTime中通過enqueueMessage方法將Message放入消息隊列中遇骑。
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) {
//將Message的target綁定為當(dāng)前的Handler
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
msg.target = this : 將Message的target綁定為當(dāng)前的Handler .
-
queue.enqueueMessage(msg, uptimeMillis): queue 是當(dāng)前Handler的消息隊列MessageQueue.通過queue.enqueueMessage將Message放入消息隊列卖毁。
?
post 方式發(fā)送消息
post(Runnable r)
postAtTime(Runnable r, long uptimeMillis)
postAtTime(Runnable r, Object token, long uptimeMillis)
-
postDelayed(Runnable r, long delayMillis)
其中post 和 postDelayed 最后還是調(diào)用sendMessageDelayed方法。postAtTime最后調(diào)用sendMessageAtTime方法落萎,最終的調(diào)用和sendMessage一樣亥啦。
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
可以看到內(nèi)部調(diào)用了getPostMessage方法,該方法傳入一個Runnable對象练链,得到一個Message對象翔脱,getPostMessage的源碼如下:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
通過上面的代碼我們可以看到在getPostMessage方法中,我們創(chuàng)建了一個Message對象媒鼓,并將傳入的Runnable對象賦值給Message的callback成員字段届吁,然后返回該Message错妖,然后在post方法中該攜帶有Runnable信息的Message傳入到sendMessageDelayed方法中。
dispatchMessage
在Looper中可以知道在Looper.loop()中最后通過msg.target.dispatchMessage(msg)來處理Message疚沐。
看一下dispatchMessage的源碼:
/**
* 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);
}
}
post方式
這其中暂氯,首先判斷msg.callback是否為空,msg.callback是一個Runnable對象亮蛔,如果不為null,則說明這是通過post的方式發(fā)送消息痴施。內(nèi)部通過 handleCallback(msg)方式執(zhí)行。
private static void handleCallback(Message message) {
message.callback.run();
}
這樣就會執(zhí)行message.callback.run()究流,也就是Runnable的run方法辣吃。
sendMessage方法
如果msg.callback返回有null,則是通過sendMessageXXX方式發(fā)送消息芬探。
這里面接著判斷mCallback是否有值神得,即構(gòu)造函數(shù)中是否傳Callback,如果有就會調(diào)用Callback中的handleMessage灯节,如果沒有就會調(diào)用Handler中的handleMessage循头。
總結(jié)
綜合上述:handler 提供3中方式處理消息,首先先判斷是否是post方式炎疆,先嘗試Post的Runnable的run方法卡骂。
接著嘗試構(gòu)造函數(shù)的handleMessage方法,最后調(diào)用handler的handleMessage方法形入。