Handler機制主要用於異步消息的處理:當發出一個消息之後,首先進入一個消息隊列,發送消息的函數即刻返回,而另外一個部分在消息隊列中逐一將消息取出,然後對消息進行處理,也就是發送消息和接收消息不是同步的處理,這種機制適合用來處理相對耗時比較長的操作。
所以在Android中通常用來更新UI,子線程執行任務,任務執行完畢後發送消息:Handler.sendMessage(),然後在UI線程Handler.handleMessage()就會調用,執行相應處理。
Handler機制有幾個非常重要的類:
Handler:用來發送消息:sendMessage等多個方法,並實現handleMessage()方法處理回調(還可以使用Message或Handler的Callback進行回調處理)。
Message:消息實體,發送的消息即爲Message類型。
MessageQueue:消息隊列,用於存儲消息。發送消息時,消息入隊列,然後Looper會從這個MessageQueen取出消息進行處理。
Looper:與線程綁定,不僅僅侷限於主線程,綁定的線程用來處理消息。loop()方法是一個死循環,一直從MessageQueen裏取出消息進行處理。
在這裏需要注意的是:一個線程裏面只會有一個Looper和一個MessageQueue,可以有多個Handler對象,
MessageQueue是在Looper對象創建的時候一起創建的,在Handler創建之前該線程必須先創建好Looper對象,否則將會報以下錯誤:
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
整個工作流程圖如下:
接下來開始工作流程源碼的分析:
源碼的分析是根據使用步驟進行:
1.先創建一個Handler
/**
* 此處以 匿名內部類 的使用方式爲例
*/
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
}
};
當我們在主線程當中,可以直接進行Handler的創建。如果是在子線程當中,在創建之前必須先初始化Looper,否則會RuntimeException;
public Handler(Callback callback, boolean async) {
// 省略部分的代碼
// 那當前線程的Looper,如果爲空拋異常
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 獲得MessageQueue的對象,當Looper創建的時候同時會創建MessageQueue對象
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
在子線程中使用handler除了必須先初始化Looper對象之外,還必須在最後調用Looper.loop()來啓動循環,否則Handler仍然無法正常接收。
而我們平時在主線程中創建handler之所以不用再去創建Looper對象是因爲主線程在初始化的時候就已經跟着創建了一個Looper,就在ActivityThread的main方法裏面
public static void main(String[] args) {
// 省略部分代碼
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
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();在這裏也是會放到最後才執行,開啓一個循環,當Looper.loop();意外退出的時候將會拋異常
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
再點進Looper.prepareMainLooper();裏面,接着往下看可以發現其內部也是調用了prepare(false);方法
public static void prepareMainLooper() {
// 在這個方法裏面會創建一個Looper,同時quitAllowed傳false意思是Looper不允許結束循環
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
// 創建Looper的方法
private static void prepare(boolean quitAllowed) {
// 通過ThreadLocal將Looper與當前的線程綁定,也意味着每個線程都是隻有唯一個Looper,當你創建第二個的時候則會報錯
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
// 創建Looper時候調用的構造函數
private Looper(boolean quitAllowed) {
// 只有當Looper創建的時候纔會同時創建 MessageQueue 對象,所以一個線程裏面只會存在一個Looper和一個MessageQueue
// 同時對應多個的Handler和Message,而且Looper和MessageQueue都是在Handler和Message尚未創建之前就已經創建好的
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
2.當我們使用Handler進行發送消息的時候
Handler發送消息的方式有很多種,包括髮送延時,即時或空的消息,或者是一個Runnable,查看相關的源碼我們會發現最終都是調用了同一個方法MessageQueue的enqueueMessage();
// Handler發送消息最終會走到的方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 最後調用了MessageQueue#enqueueMessage(msg, uptimeMillis);
return queue.enqueueMessage(msg, uptimeMillis);
}
繼續追蹤點開查看MessageQueue的enqueueMessage();的全部源碼
boolean enqueueMessage(Message msg, long when) {
//Meesage是否可用
//這裏的msg.target指的就是發送該Message的Handler
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) {
// 判斷是否調用了quit()方法,即取消信息;如果調用了,說明Looper已經停止了,同時所有的消息都已經被取消
// 需要注意的是如果是主線程調用quit()方法將會拋異常
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 {
// 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.
// 如果Looper.loop()是休眠狀態,則調用native方法喚醒loop()
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
需要注意的一點是,在MessageQueue中Message的保存是以鏈表的形式存儲的,即只有上一個的Message才知道它的下一個Message是誰,而當前的MessageQueue也是不知道的
然後再從Looper.loop()方法中取出消息,繼續追蹤源碼如下:
public static void loop() {
// 獲取當前Looper的消息隊列,其中myLooper()作用:返回sThreadLocal存儲的Looper實例;若me爲null 則拋出異常;
// 即loop()執行前必須執行prepare(),從而創建1個Looper實例
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// 省略中間的部分源碼。。。
// 開啓循環取出消息
for (;;) {
// 從消息隊列中取出消息,如果是沒有消息的話,在queue.next();阻塞線程
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// 省略中間部分代碼
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
// 將取出的消息派發到對應的Handler
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
// 省略部分代碼。。。
// 釋放消息所佔用的資源
msg.recycleUnchecked();
}
}
// 在Looper.loop()中調用了MessageQueue#next()源碼如下
Message next() {
// 省略部分的代碼。。。
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// nativePollOnce方法在native層,若是nextPollTimeoutMillis爲-1,此時消息隊列處於等待狀態
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 從隊列裏面取出消息,如果消息爲空的話,nextPollTimeoutMillis = -1,則會阻塞線程,此時消息隊列進入等待的狀態
if (msg != null && msg.target == null) {
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();
return msg;
}
} else {
// 沒有消息的時候
nextPollTimeoutMillis = -1;
}
// 省略部分代碼。。。
// 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;
}
}
當消息從Looper.loop()中被取出就會分調用了相對應的Handler#dispatchMessage()傳遞消息
// Handler#dispatchMessage的源碼如下,在Looper.loop()中被調用
public void dispatchMessage(Message msg) {
// 先判斷了當前的消息類型是否Handler.post()時使用Runnable
if (msg.callback != null) {
// 如果是傳入的Runnable則調用此方法,會調用Runnable.run()
handleCallback(msg);
} else {
if (mCallback != null) {
// 如果在創建Handler時候傳入自定義Callback,則會調用此方法,並且可以限定Handler#handleMessage()是否執行
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果都沒有則調用Handler#handleMessage()方法
handleMessage(msg);
}
}
到此整個的Handler機制和源碼也分析得差不多了!!!
字比較多,寫得好累