前言
本文分析了Hander幾個重要類以及他們之間的關係。Handler
是Android SDK
來處理異步消息的核心類。
子線程與主線程通過Handler來進行通信。同時在應用的整個生命週期裏也起着至關重要的作用。
源碼分析
ActivityThread
中也使用到了Looper循環,那麼看下它裏面是怎麼使用。
先看下ActivityThread
的main函數裏面:
public static void main(String[] args) {
Looper.prepareMainLooper();
...
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
首先是調用prepareMainLooper
做一些初始化的操作,接下來就是調用Looper.loop()來啓動死循環處理消息。
在看下thread.attach(false)
。他的作用就是將ApplicationThread
對象與AMS關聯起來,然後通過Handler通知主線程執行對應操作。
這個Handler是ActivityThread
裏面定義的,貼上部分代碼:
private class H extends Handler {
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
...
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case UNBIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
handleUnbindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
常用生命週期正是在這個Hander裏面執行的,可見這個Looper承載着整個應用生命。
OK!大概說明下Handler的處理機制:handler
發送Message
給MessageQueue
,Looper
不斷的遍歷消息然後通知Handler
處理。如下圖所示:
0、
1、初始化
Looper的初始化有兩種。prepareMainLooper
()和prepare
()。在子線程定義Handler的時候需調用prepare()方法,而UI
線程已經定義了一個prepareMainLooper
所以無需再執行。
先看看prepare()
方法:
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));
}
參數quitAllowed
顧名思義就是true
的時候允許quit
操作。
看下sThreadLocal.set
方法,他的作用就是將新建的Looper對象和當前線程綁定起來。
接着看下new Looper構造方法:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
沒什麼內容,主要就是新建一個MessageQueue
存入mQueue
。接下來看下MessageQueue
構造方法:
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
也沒什麼主要是將參數quitAllowed
賦值給mQuitAllowed
。
總的來說就是New出一個Looper和當前的線程綁定還有new處一個MessageQueue
賦值給mQueue
。
下面看下prepareMainLooper()
方法:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
其實也就是比prepare()
方法多了sMainLooper = myLooper()
操作,就是將主線程的Looper
賦值給sMainLooper
。還有就是prepare的參數爲false
即不允許quit
。
2、啓動Looper循環處理消息Looper.loop()
public static void loop() {
final Looper me = myLooper();//標註1
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//標註2
for (;;) {
// might block
Message msg = queue.next(); //標註3
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
msg.target.dispatchMessage(msg);//標註4
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
msg.recycleUnchecked();//標註5
}
}
標註1處先取出當前線程綁定的Looper,標註2處取出該Looper的mQueue
也就是prepare的時候新建的mQueue
。
獲得當前線程對應的MessageQueue
之後,接下來用了一個死循環操作Message
對象。
標註3處是遍歷queue鏈表的元素。
標註4是執行Message元素的dispatchMessage
方法,貼上代碼:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
注意這邊的msg.target
是Message
對象綁定的Handler對象,稍後會介紹。這邊的msg.callback
爲NULL,那麼就會調用handleMessage(msg)
方法也就是調用Handle創建的時候handleMessage
實現。
標註5回收該Message
元素。
也就是說該死循環內先從MessageQueue
取出Message
對象,執行dispatchMessage
方法,然後回收Message
對象。
重點看下queue.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 long ptr = mPtr;
if (ptr == 0) {//標註1
return null;
}
for (;;) {
...
nativePollOnce(ptr, nextPollTimeoutMillis);//標註2
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;//標註7
...
if (msg != null) {
if (now < msg.when) {//標註3
// 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;//標註4
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;//標註5
}
msg.next = null;
...
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {//標註2
dispose();
return null;
}
}
}
}
首先是返回null也就是退出Looper的兩個位置:1、標註1處ptr == 0
的時候,百度上看到消息隊列被釋放的時候,由於涉及到native後續再看。2、mQuitting
標誌爲true,mQuitting
只會被以下方法設置:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
...
}
}
首先是mQuitAllowed
標誌爲false(也就是prepareMainLooper
初始化的時候設置爲false)的時候直接報錯,因爲主線程不允許退出looper循環。因爲主線程一退出循環,整個應用就退出了。接下來就是設置mQuitting
爲true,那麼說明quit方法的作用也就是退出Looper。
那quit方法什麼場景會用到呢?
看下ActivityThread
的H的handleMessage
方法:
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
當EXIT_APPLICATION標誌的時候便會調用該方法。但是這邊有個疑惑:當的時候會報錯"Main thread not allowed to quit."
,不知道是否是這樣子的邏輯。Mark一下。
下面再回到next()方法中的死循環代碼塊:
標註6處Message msg = mMessages
,將當前Message的下一個對象存入msg
。
標註3處當now < msg.when
的時候也就是還沒到Message執行時間,計算出nextPollTimeoutMillis
時間下次循環的時候繼續等待 。
標註2處nativePollOnce(ptr, nextPollTimeoutMillis)
,他的作用是等待nextPollTimeoutMillis
毫秒的時間。
標註4處mBlocked = false
,注意這個標誌。在Handler發送消息會有用到。
標註5處mMessages = msg.next
,將當前msg
的下一個對象存入mMessages
。
最後就是返回msg
。
總的來說就是:如果還沒到執行時間那麼計算等待時間繼續等,如果到了執行時間標誌置爲false然後返回下一個Message對象。
3、Handler發送消息
發送消息通常有兩種方式,貼上代碼:
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//doSomething
}
};
mHandler.obtainMessage().sendToTarget();
mHandler.post(new Runnable() {
@Override
public void run() {
//doSomething
}
});
首先是Handler的構造函數,貼上代碼:
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
}
Looper.myLooper()
就是從當前線程獲取綁定的Looper對象,所以說當在UI
線程新建Handler對象的時候不用考慮Looper的問題。接下來就是在該Looper傳給mQueue
。
首先看下mHandler.obtainMessage().sendToTarget()
。
public final Message obtainMessage(){
return Message.obtain(this);
}
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
obtain()是從對象池裏面取出一個Message對象避免每次都new對象。然後將mHandler
賦值給Message對象的target。
OK!那看下sendToTarget
方法:
public void sendToTarget() {
target.sendMessage(this);//標註1
}
target就是剛纔mHandler
,而this就是mHandler.obtainMessage()
。然後一直跟下去就到了sendMessageAtTime
方法。
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);//標註2
}
標註1的就到了標註2,參數queue就是mHandler
構造的時候由線程對應Looper
對象獲取的。enqueueMessage(queue, msg, uptimeMillis)
最終是跑到MessageQueue
中的enqueueMessage
方法,貼上代碼。
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
...
msg.when = when;
Message p = mMessages;//標註1
boolean needWake;
if (p == null || when == 0 || when < p.when) {//標註2
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {//標註3
...
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
...
}
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;
}
標註1處mMessages
就是下一個要執行的Messages對象,將它賦值給p。
標註2處when是當前Message的執行時間而p.when也就是當前MessageQueue
裏最早的執行時間。
如果when比最早的執行時間還早的話分爲兩步處理:
第一步就是排到MessageQueue
對前面。
第二部是考慮到兩種情況。MessageQueue
是否正在處理也就是mBlocked
是否爲false。如果爲ture
也就是說looper正在阻塞狀態那就要利用nativeWake
方法喚醒。
標註3處如果when比最晚的執行時間還早的話就按時間先後插入MessageQueue
鏈表中。
OK,下面看下mHandler.post
方式發送消息:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
和其他方法大同小異。主要是差在getPostMessage(r)
,看下代碼:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
最終也是將Message對象交給MessageQueue
中,那麼就會執行到dispatchMessage
方法。最終會跑到handleCallback
方法
private static void handleCallback(Message message) {
message.callback.run();
}
最終調用了Runnable實現。