從事Android開發(fā)經(jīng)常使用的Handler來進行異步操作,網(wǎng)上也有較多的說明,但是講解得都太淺了,只能知道期大概原理,本章從源碼角度來分析Hnadler機制。牽扯到的類有Handler,Message, MessageQueue, Looper。
Handler : 一個Handler允許在允許的線程中發(fā)送跟處理消息和Runnable對象。每個Handler對象跟單個線程以及線程中的消息隊列關(guān)聯(lián)在一起。
Message: 消息包含一個描述和任意的數(shù)據(jù)對象,可以使用Handler發(fā)送到消息隊列中。這個對象包含兩個額外的int字段和一個額外Object字段。
MessageQueue:用來存放線程放入的消息,要通過handler? sendMessage來添加消息,它的處理跟Looper有關(guān)。
Looper: 類用于運行一個消息循環(huán)的線程。
先分析Hanlder類:
其構(gòu)造方法有好幾個:
public Handler() {}
publicHandler(Callback callback) {}
publicHandler(Looper looper) {}
publicHandler(booleanasync){}
publicHandler(Callback callback,booleanasync) {}
publicHandler(Looper looper, Callback callback,booleanasync) {}
需要注意的地方,構(gòu)造可以看出有一個Looper對象的構(gòu)造,此構(gòu)造會把Hanlder跟Looper綁定,如果是子線程中的Looper那么Handler處理的消息也將在子線程中。
Callback對象如果不為空的話,將使用Callback來處理Message。
大家經(jīng)常使用有 sendEmpryMessage系列,SendMessage系列,post(Runnable)系列,而這些所有的發(fā)送消息的方法最后是都運行到 public boolean sendMessageAtTime(Message msg,long uptimeMillis),在此方法內(nèi)把Message 插入到MessageQueue中,并根據(jù)uptimeMillis來判斷插入的位置。
先分析一下各種send 跟 post 如何跳轉(zhuǎn)到sendMessageAtTime這個方法的。
public final boolean sendEmptyMessage(intwhat){
return sendEmptyMessageDelayed(what,0);} //sendEmptyMessage(what) 其實跟sendEmptyMessageDelayed是一樣的,只不過延時為0
再看public final boolean sendEmptyMessageDelayed(intwhat,long delayMillis) {
Message msg = Message.obtain();
msg.what= what;
return sendMessageDelayed(msg, delayMillis);}
把What進行了一下封裝,畢竟Message存的都是Message
public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg,0);}
再看public final boolean sendMessageDelayed(Message msg,longdelayMillis){
if(delayMillis <0) { delayMillis = 0;}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}
// 所謂延時就是在現(xiàn)在的基礎(chǔ)上 加上要延時的時間就是要執(zhí)行的時間
public boolean sendMessageAtTime(Message msg,longuptimeMillis) {
MessageQueue queue =mQueue;
if(queue ==null) {
RuntimeException e =newRuntimeException(
this+" sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
??? returnenqueueMessage(queue, msg, uptimeMillis);
}
sendMesage系列跟sendEmptyMessage系列到sendMessageAtTime()的核心代碼都已經(jīng)貢上。
再看post系列public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r),0);}
private staticMessage getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback= r;
returnm;}
這個就不難理解了,獲取一個新的Message把Runnable放置到的Message中,再調(diào)用SendMessage系列的函數(shù)。
同樣的post系列就不多解析了,上源碼 :
public final boolean postDelayed(Runnable r,longdelayMillis){
return sendMessageDelayed(getPostMessage(r), delayMillis);}
public final boolean postAtFrontOfQueue(Runnable r)
{ return sendMessageAtFrontOfQueue(getPostMessage(r));}
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue =mQueue;
if(queue ==null) {
RuntimeException e =newRuntimeException(
this+" sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg,0);
}? // 此處直接調(diào)用到 enqueueMessage(queue, msg,0) 沒有走到sendMessageAtTime()
現(xiàn)在來說下private boolean enqueueMessage(MessageQueue queue, Message msg,longuptimeMillis) {
msg.target=this;
if(mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
} 最終將調(diào)用到消息隊列的enqueueMessage方法。
在講解enqueueMessage的方法之前,要先把Message這個類要說下,要處理的數(shù)據(jù)來源都是此類的。
public final classMessageimplementsParcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
/*package*/long when;
/*package*/Bundle data;
/*package*/Handler target;
/*package*/Runnable callback;
// sometimes we store linked lists of these things
/*package*/Message next;
} what arg1 arg2 obj這幾個方法大家都熟悉,就是要處理的數(shù)據(jù),里面還有個Bundle data,大家也是可以用來通過 getData() /peekData() 跟 setData() 存取數(shù)據(jù)。 而when呢,就是enqueueMessage函數(shù)的最后一個參數(shù),用來表示是什么時候要運行的,插入到MessageQueue跟MessageQueue中取出Message也是通過此變量來做判斷依據(jù)的。target 就是代表被哪個Handler放置到消息隊列中的,在Message被取出時,也就是由那個Handle對象來處理的。而callback呢? 在前面的代碼中應(yīng)該看見過了( 見getPostMessage),post的runnable就是賦值給了message的callback,具體什么時候被調(diào)用請往下看。
next變量 這個又是啥東西呢,熟悉列表跟隊列的同志應(yīng)該清楚,列表只用一個引用一個頭就好了,那么MesageQueue也是一樣的,MessageQueue中其實只存了一個Message對象,遍歷是通過其next對象來遍歷的。
還有幾個大家可能使用到函數(shù)的代碼也貼一下源碼,都比較簡單,就請各位自己品味了。
public Bundle getData() { // 得到bundle數(shù)據(jù)
if(data==null) {
data=newBundle();
}
return data;
}
public voidsetData(Bundle data) {
this.data= data;
}
publicBundle peekData() {
returndata;
}
public voidsendToTarget() {
target.sendMessage(this);
}
public staticMessage obtain() {? //從全局池返回一個新的消息實例。讓我們在許多情況下避免分 //配新對象。
synchronized(sPoolSync) {
if(sPool!=null) {
Message m =sPool;
sPool= m.next;
m.next=null;
m.flags=0;// clear in-use flag
sPoolSize--;
return m;
}
}
return newMessage();
}
現(xiàn)在說一下MessageQueue,通過Handle跟Message的一些說明,那么了解MessageQueue就簡單多了,其實也是蠻復(fù)雜的,但是我們只關(guān)心我們要關(guān)心的就可以了,只要看enqueueMessage這個方法就好了。
boolean enqueueMessage(Message msg, longwhen) {
// xxxx?
//xxx
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);
}
}
return true;
}
主要做的就是根據(jù)when來確定新插進來的Message要插入到那個地方(需要注意的MessageQueue只有隊列頭的引用),并給When賦值給Message的when。
現(xiàn)在來看最終的Looper,里面主要有一個如何取出Message的方法,比較復(fù)雜
looper里面有一個MessageQueue,調(diào)用Loop方法后就開啟了循環(huán)檢測看Loop方法
/**
* Run the message queue in this thread. Be sure to call
* {@link#quit()} to end the loop.
*/
public static voidloop() {
finalLooper me =myLooper();
if(me ==null) {
throw newRuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
finalMessageQueue 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 longident = Binder.clearCallingIdentity();
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);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final longnewIdent = 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();
}
}
可以看到在for循環(huán)是個死循環(huán)里面都要用了MessageQueue的Next方法,看MessageQueue的next方法
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final longptr =mPtr;
if(ptr ==0) {
return null;
}
intpendingIdleHandlerCount = -1;// -1 only during first iteration
intnextPollTimeoutMillis =0;
for(;;) {
if(nextPollTimeoutMillis !=0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized(this) {
// Try to retrieve the next message.? Return if found.
final longnow = SystemClock.uptimeMillis();
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();
returnmsg;
}
}else{
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if(mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if(pendingIdleHandlerCount <0
&& (mMessages==null|| now
pendingIdleHandlerCount =mIdleHandlers.size();
}
}
mPendingIdleHandlers=mIdleHandlers.toArray(mPendingIdleHandlers);
}
if(!keep) {
synchronized(this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount =0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis =0;
}
}
說實在話沒有看懂,但是結(jié)果就是Loop根據(jù)When循環(huán)出去MessageQueue里面的Message
取出后調(diào)用msg.target.dispatchMessage(msg);
也就是Handler里面的派發(fā)消息 dispatchMessage。轉(zhuǎn)了半天終于回到了Handler。有幾個地方要注意的一個線程只有一個MessageQueue 一個Looper, 但是Handler跟Message是可以有多個。來看dispathMessage這個方法:
public voiddispatchMessage(Message msg) {
if(msg.callback!=null) {
handleCallback(msg);
}else{
if(mCallback!=null) {
if(mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
private static voidhandleCallback(Message message) {
message.callback.run();
}
}
以上代碼的意思是? 如果Message中的callback不為空,就調(diào)用callback中的run方法,也就是Post里面的那個Runable
如果Handler里面的Callback(前面構(gòu)造有說)不為空,就是調(diào)用CallBack里面的handleMessage() 方法, 如果不是以上2種情況就是Handler自己要重載處理handleMessage()的方法
從SendMessage到HandlerMesage的方法都已經(jīng)說完了??傮w來說
1.Handler發(fā)送各種消息, 然后對各種消息進行封裝成Message對象
2.根據(jù)時間把Mesage插入到Looper的MessageQueue中,并把Message標(biāo)上時間
3.loop循環(huán)取出Message(此步驟最為復(fù)雜了,好幾個地方?jīng)]有想通,里面也調(diào)用了好幾個native方法)
4.取出之后對Message進行派發(fā)處理。
打個比喻:有3個人(Hanlder)H1,H2,H3, 他們有一些包裹(Message),每個包裹上都標(biāo)注了什么時候取出來,H1, H2,H3把他們的包裹存進銀行(MessageQueue)里,存進銀行的時候包裹上被標(biāo)記是誰(H1, H2, H3)的包裹,并按照要取出的時間的順序進行了排序,銀行的工作人員(Loop),會不斷的檢查包裹是否要取出來了,到了指定的時間取出時間,包裹被工作人員打開。根據(jù)包裹上標(biāo)記的,寄送給被標(biāo)記的人H1 H2 或者H3。在H1 H2 或者H3收到之后,查看包裹里面是否寫有包裹里面的東西要給誰(Message的CallBack),如果包裹上寫了要給誰,那么就給那個人處理(Message的CallBack也就運行了)。如果沒有寫給誰出來,那么H1看下是否有認識的人(H1的Callback)能處理這個包裹,如果有那就給CallBack處理,如果沒有那么就只能自己來出來了(要重載HandleMessage方法)。
另外要注意的是post 的runnable的那個Message的what方法是沒有賦值的,也就是默認值0, 所以最好大家自己發(fā)送message的時候不要把message的what賦值為0 或者不賦值,以免引起不必要的麻煩。
Handler是可以跟子線程綁定在一起的,并不是只能運行在UI線程中的,Android的UI線程默認是調(diào)用了prepare()跟Loop()的。
例如 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();
?? ? }
插個圖:解析 2個Handler對象H1 H2向MessageQueue發(fā)送Message,此時MessageQueue中已經(jīng)有3個Message了其中有一個來自H1 2個來自H2.而且H1的一個Message被取出了,根據(jù)Message的信息做對應(yīng)的處理。

不得不吐槽一下簡書的排版,代碼copy過來的排版真不好處理(不知道是不是我會用),希望官方給一個好的排版。