android2010-01-18 15:06:23閱讀484評論0 字號:大中小 訂閱
轉載時(shí)請注明出處和作者聯(lián)系方式
文章出處:http://www.limodev.cn/blog
作者聯(lián)系方式:李先靜 <xianjimli at hotmail dot com>
前幾天和一位同事討論Android中Handler和Thread,其中一個(gè)問(wèn)題是:創(chuàng )建Handler時(shí)會(huì )不會(huì )創(chuàng )建Thread?
我對JAVA編程不熟,但直覺(jué)告訴我不會(huì ):我認為Handler只是用來(lái)輔助實(shí)現異步操作的東西。當時(shí)我拿了GTK+中的idle來(lái)做對比,sendMessage就相當于加一個(gè)idle函數,系統處理完前面的Message后就會(huì )處理這個(gè)Message。畢竟沒(méi)有看過(guò)里面的實(shí)現代碼,所以當時(shí)并不確信。今天看了下:
MessageQueue
消息隊列MessageQueue是一個(gè)以執行時(shí)間為序的優(yōu)先級隊列:
o 普通消息的執行為當前時(shí)間,先發(fā)送的前面,后發(fā)送在后面,這是典型的FIFO。
o 最高優(yōu)先級的消息執行時(shí)間為0,所以直接插在隊列的最前面,通常會(huì )立即執行。
o 而在將來(lái)執行的Message相當于timer,執行時(shí)間為當前時(shí)間+delay的時(shí)間。
MessageQueue的函數boolean enqueueMessage(Message msg, long when)用來(lái)向隊列中插入消息。
Message和GTK+ idle不同之處在于,Message只是一段數據,里面說(shuō)明了要做什么,但不并知道如何做。而idle帶有自己的數據和處理函數,它知道如何做。Message放入隊列中后,在處理這些消息時(shí)到底要做些什么呢?這就引入了Handler:
Handler
Handler對消息隊列的enqueueMessage做了包裝,這其實(shí)并不重要,因為完全可以直接調用enqueueMessage來(lái)實(shí)現。重要的Handler把在包裝enqueueMessage的同時(shí),把Message的target設成了自己,即為Message指定執行的行為:
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
這樣一來(lái),當前Message被處理的時(shí)候就會(huì )調用Handler的dispatchMessage,而這個(gè)函數就會(huì )調用你要實(shí)現的虛函數handleMessage了。經(jīng)過(guò)消息隊列轉了一圈,還是調用了你自己的實(shí)現函數,但是同步操作變成了異步操作。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Looper
Message放在消息隊列里了,誰(shuí)來(lái)一個(gè)一個(gè)的取出來(lái)處理呢?這時(shí)輪到Looper上場(chǎng)了,它的函數loop會(huì )一直循環(huán)處理隊列中的消息,直到遇上一個(gè)沒(méi)有target的Message:
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
由此可見(jiàn):一個(gè)Looper總是和一個(gè)MessageQueue關(guān)聯(lián)起來(lái)的。
Thread
loop只是一個(gè)函數,它也需要別人來(lái)執行它。由于它一執行就會(huì )阻塞在那里,所以一定需要一個(gè)線(xiàn)程來(lái)調用:
* 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();
* }
* }
一個(gè)Looper也總是和一個(gè)Thread關(guān)聯(lián)起來(lái)的,不過(guò)不一定要創(chuàng )建新線(xiàn)程,可以是主線(xiàn)程的。Handler和Thread不是一一對應的,理論上,在一個(gè)LooperThread中,可以有任何多個(gè)Handler,每個(gè)消息都可以指定不同的Handler,因為每個(gè)消息都可以有不同的行為。
在創(chuàng )建Handler時(shí)并不會(huì )創(chuàng )建Thread,它只是取當前線(xiàn)程的Looper的MessageQueue:
public Handler() {
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 = null;
}
通過(guò)myLooper取出當前線(xiàn)程的Looper:
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
這個(gè)Looper是在Looper.prepare里創(chuàng )建的:
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
聯(lián)系客服