Handler源碼解析
剛?cè)胄蠥ndroid那會翰意,看過好多遍這方面的不同的博客结榄,每次看完都似懂非懂歇盼,今天我打算自己來分析一下Handler機制及其相關(guān)源碼违寿。
主要涉及以下幾個類:
- Handler
- MessageQueue
- Looper
- Message
看一下官方對Handler這個類的解釋:Handler允許你向其發(fā)送Message或者是post Runnable,一個Handler只能綁定一個線程以及線程對應(yīng)的MessageQueue扫倡。當我們創(chuàng)建一個新的Handler的時候谦秧,它就和創(chuàng)造它的時候所在的線程以及線程對應(yīng)的MessageQueue綁定了,它將用來將messages和runnables傳送給MessageQueue撵溃,以及執(zhí)行他們當他們從MessageQueue隊列中被pop出來的時候疚鲤。
Handler有兩種用處:一是用來執(zhí)行同一線程中的messages以及runnables,二是在另一個線程中執(zhí)行缘挑。
發(fā)送消息的方式有很多種集歇,主要是由以下方法來完成的:
一類是post runnable
post
postAtTime
postDelayed
一類是send message
sendEmptyMessage
sendMessage
sendMessageAtTime
sendMessageDelayed
這些方法能夠讓你控制是現(xiàn)在執(zhí)行,還是需要延遲多長時間來執(zhí)行语淘。
當我們開啟一個應(yīng)用時诲宇,即開啟了一個進程际歼,應(yīng)用的主線程就會開啟一個MessageQueue隊列用來管理最重要的一些對象,如Activity和廣播焕窝,你可以創(chuàng)建一個子線程,通過Handler來與主線程或者應(yīng)用來進行通信维贺,當合適的時候它掂,這些runnable或者message會被執(zhí)行。
通過大概翻譯官方注釋溯泣,我們可以發(fā)現(xiàn)Handler主要是用來做線程間通信的虐秋,分析Handler我們主要分析上面提到的兩類方法:1.post runnable 2.send message
我們先分析send 系列方法:
??通過查看源碼,我們可以發(fā)現(xiàn)垃沦,不論是sendMessage客给,還是sendMessageDelayed還是sendEmptyMessage,最終都會調(diào)用sendMessageAtTime方法肢簿。這里面涉及到一個Message對象靶剑,我們稍后來分析,最終會走到enqueueMessage方法池充,enqueueMessage方法會走到MessageQueue里面的enqueueMassage桩引。待會我們一起分析。
我們再來看post runnable系列方法:
??通過查看源碼收夸,我們可以發(fā)現(xiàn)坑匠,最終也是走到sendMessageAtTime方法,然后調(diào)用enqueueMessage卧惜。只不過厘灼,在這個過程中,創(chuàng)建了一個Message實例咽瓷,并將runnable賦給了message的callback设凹。
Handler我們先分析到這里。
下面我們來分析Message這個類:
Message這個類的數(shù)據(jù)結(jié)構(gòu)可以說是一個單鏈表茅姜,它有幾個重要的成員變量:
- next 指向鏈表下一item的引用
- what 用來區(qū)別是哪一類消息围来,相當于一個type
- target 用來保存所屬Handler的引用
- callback 用來保存要執(zhí)行的任務(wù)runnable
其他還包括arg1,arg2 匈睁,object等监透,這些就不一一解釋了
Message類還有一個重要方法:obtain。
當我們創(chuàng)建一個Message對象時航唆,我們可以new胀蛮,也可以通過Message.obtain方法來獲取一個實例。官方推薦后者糯钙,
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message 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 new Message();
}
意思就是說粪狼,這種方式能夠避免重復(fù)創(chuàng)建新對象退腥。從代碼可以看出,只有當Message回收池為空的時候才會去new一個Message再榄。那么這個Message回收池是什么時候建立的呢狡刘,以及什么時候往里面放對象的呢?我們找到recycleUnchecked這個方法,可以發(fā)現(xiàn)這個方法就是將Message的flag置為FLAG_IN_USE困鸥,并且清空其他參數(shù)嗅蔬,并將其加入到緩存池。這個方法是在MessageQueue執(zhí)行enqueueMessage的時候才會調(diào)用疾就。
下面我們來分析MessageQueue這個類:
首先澜术,看它的構(gòu)造,除了傳了一個參數(shù)猬腰,其它的都在native處理了鸟废,我們也看不見什么,感興趣的可以去看一下native層代碼姑荷。
再看一下MessageQueue的數(shù)據(jù)結(jié)構(gòu)盒延,我們可以發(fā)現(xiàn)它其實是一個優(yōu)先級隊列。
隊列的插入以及移除item有兩個重要方法:
第一個是我么上面提到的enqueueMessage方法:這個方法主要是向隊列中插入Message對象:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
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 {
//這里是往中間插入,循環(huán)鏈表觸發(fā)時間,找到對應(yīng)的插入位置
// 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;
}
第二個就是MessageQueue的next方法,這個方法主要處理的是MessageQueue的出隊操作,即從隊頭開始一個個執(zhí)行移除.代碼太多,就不貼過來了,主要部分就是指針后移:
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();
return msg;
那么,什么時候才會執(zhí)行next的方法呢?這就得來到Looper這個類了.
Looper這個類,每個線程都只有一個,跟線程綁定.我們看一下他的主要方法:
public static void loop() {
final Looper me = myLooper();
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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
msg.recycleUnchecked();
}
}
從上面的代碼可以發(fā)現(xiàn),loop差不多就是一個死循環(huán),只有當MessageQueue為空的時候,才會退出.Looper當中有兩個重要的地方:
第一個是 Message msg = queue.next(),從隊列中取出一個Message,
第二個是 Message msg = queue.next(),這個方法最終會調(diào)用message對應(yīng)handler的dispatchMessage方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
當msg的callback不為空時,執(zhí)行callback.run,如果為空的話則判斷在創(chuàng)建Handler的時候有沒有給mCallback賦值,如果有,則走mCallback里面的handleMessage方法,如果沒有則走Handler的handleMessage方法.
但是,在實際開發(fā)當中,我們發(fā)現(xiàn)我們并沒有創(chuàng)建Looper,也沒有調(diào)用Looper的loop方法,為什么也能夠執(zhí)行到我們重寫的handleMessage方法呢?
這是因為,我們一般是在主線程即UI線程中創(chuàng)建的Handler,而在主線程中是默認創(chuàng)建了Looper的.看代碼:
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
這段代碼是截取自ActivityThread的main函數(shù),在我們應(yīng)用啟動的時候,就執(zhí)行了這個函數(shù).
至此,我們把Handler機制的重要代碼都分析完了!!
總結(jié)一下:畫個圖,看懂你就贏了