版權(quán)聲明
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處+地址
什么是Handler消息機(jī)制
Android內(nèi)部的Handler消息機(jī)制,是將子線程處理的結(jié)果,通過Handler異步回調(diào)給主線程,讓主線程去進(jìn)行操作的一個(gè)機(jī)制。
Handler消息機(jī)制的工作流程圖

Handler的源碼解析
Handler使用案例
首先,給大家簡單的展示下Handler的使用流程代碼
/**
* Function:簡述Handler使用方式
*
* @author wanzi Created on 2019/4/28
*/
public class HandlerActivity extends AppCompatActivity {
private MyHandler mHandler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new MyHandler();
Executors.newSingleThreadScheduledExecutor().schedule(new Runnable() {
@Override
public void run() {
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
}
}, 5000, TimeUnit.MILLISECONDS);
}
private static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
Log.d("HandlerTestActivity", "Handler發(fā)來賀電");
}
}
}
}
Handler是如何將消息加入到消息隊(duì)列?
分析源碼,我們首先要找到切入點(diǎn),mHandler.sendMessage(msg),代碼從這個(gè)函數(shù)開始調(diào)用的handler,那么繼續(xù)往下追蹤,我們來研究下,在發(fā)送消息之后,Handler干了什么?
Handler.java
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
在經(jīng)過層層調(diào)用之后,我們發(fā)現(xiàn)調(diào)用到了enqueueMessage方法,根據(jù)字面意思,就是加入消息隊(duì)列,那我們繼續(xù)看里面的實(shí)現(xiàn)
Handler.java
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
- 將當(dāng)前的handler對(duì)象賦值給了msg.target
- 調(diào)用了messagequeue的enqueueMessage方法
MessageQueue.class
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
if (p == null || when == 0 || when < p.when) {
...
} else {
...
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
...
}
return true;
}
到此為止,msg算是終于成功的加入到消息隊(duì)列當(dāng)中,當(dāng)然MessageQueue.enqueueMessage的內(nèi)容遠(yuǎn)不止這么簡單,里面包含一些異常處理,喚醒機(jī)制等等,單獨(dú)寫一篇文章詳細(xì)的講解。
Handler如何從消息隊(duì)列獲取消息?
主線程的Looper如何創(chuàng)建?
說到獲取消息,我們還得從Looper說起,大家都知道,在主線程中創(chuàng)建的Handler對(duì)象,是自帶Looper對(duì)象的,那么主線程中的Looper是從哪里創(chuàng)建的呢?
我們知道,程序啟動(dòng)開始的入口在ActivityThread.class的main函數(shù),我們來看看代碼
ActivityThread.class
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
...
}
簡化之后,我們可以看出,在main函數(shù)中,有兩處和Looper相關(guān)的代碼,那么我們分別來看下
** Looper.class**
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
- prepareMainLooper最終調(diào)用到的是prepare函數(shù)
- prepare的quitAllowed參數(shù)值為false,意味著在主線程中,不允許退出
- 在prepare函數(shù)中,我們new了一個(gè)Looper對(duì)象,放在了一個(gè)ThreadLocal的對(duì)象中保存
- sMainLooper 是將sThreadLocal中保存的值取出,賦值給它
ThreadLocal的簡單介紹
在整個(gè)Looper的創(chuàng)建以及獲取的過程,其實(shí)主要跟ThreadLocal的set,get函數(shù)相關(guān),那么我們就來看看這兩個(gè)函數(shù)的源碼
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
- set函數(shù)雖然只需要傳value值進(jìn)來,但是其實(shí)它是獲取的當(dāng)前線程作為key值,將其保存,這也就說明為什么一個(gè)線程只對(duì)應(yīng)來一個(gè)looper,因?yàn)樗拇鎯?chǔ)的數(shù)據(jù)結(jié)構(gòu)只支持一對(duì)一的關(guān)系。
- get函數(shù)也是通過以當(dāng)前線程作為key將對(duì)應(yīng)的entry取出,返回給調(diào)用方
那么以上就是mainLooper的創(chuàng)建的主要流程
主線程的Looper如何開啟消息輪詢的呢?
大家回顧下前面ActivityThread.main方法,我們還有一行代碼沒有分析,那就是Looper.loop,根據(jù)字面意思我們也能猜出,這是開始進(jìn)行循環(huán),話不多說,上代碼
Looper.class
public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
...
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
}
這里我們同樣省略了很多源碼,只分析主要流程
- 通過myLooper()獲取到當(dāng)前線程的looper對(duì)象,上面也帶大家一起分析過源碼了,有不清楚的可以回過去看看
- 通過拿到的looper對(duì)象去獲取到當(dāng)前的消息隊(duì)列
- 進(jìn)入死循環(huán)
- 不斷的從隊(duì)列中獲取新的消息
- 獲取到消息后,msg.target.dispatchMessage(msg)
以上就是Looper開啟輪詢的整個(gè)調(diào)用流程。
下面我?guī)Т蠹乙黄鹂聪聨讉€(gè)問題:
-
MessageQueue.next是如何拿到message的呢?
MessgeQueue.class
Message next() {
...
for (;;) {
...
synchronized (this) {
...
Message prevMsg = null;
Message msg = mMessages;
...
if (msg != null) {
if (now < msg.when) {
...
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
...
msg.markInUse();
return msg;
}
} else {
...
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
...
}
- 在next函數(shù)中也有一個(gè)死循環(huán),當(dāng)獲取到我們的msg之后,跳出循環(huán)
- next函數(shù),就是從當(dāng)前的message獲取到nextMessage,并將其返回給looper
看完之后,你一定還有很多疑問,為什么要用到死循環(huán)?當(dāng)消息隊(duì)列為空的時(shí)候,next函數(shù)會(huì)怎么辦?等等等等,跟MessageQueue.enqueueMessgae方法一樣,next函數(shù)的實(shí)現(xiàn)大有文章,單獨(dú)為大家寫一篇詳細(xì)介紹,這里只作簡單的流程分析。
-
什么情況下msg為空,跳出整個(gè)循環(huán)呢?
這一塊先跟大家簡單的介紹一下,在next函數(shù)中,我們發(fā)現(xiàn)有return 為 null的情況,取決于一個(gè)叫mQuitting的參數(shù),其實(shí)就是調(diào)用了MessageQueue.quit()方法,將其設(shè)置為true。但是在主線程中,大家還記得我們?cè)贚ooper.prepare傳入的false參數(shù)嗎?它不允許主線程的MessageQueue執(zhí)行quit方法,直接拋出異常。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
-
msg.target.dispatchMessage(msg)是怎么回調(diào)到handler.handleMessage方法的呢
** Message.class **
/*package*/ Handler target;
是的,正如上面我們所預(yù)料的,target其實(shí)是一個(gè)handler的對(duì)象,在Handler.enqueueMessage方法中,我們將msg與handler進(jìn)行了關(guān)聯(lián),那么在Looper.loop里面,msg.target.dispatchMessage(msg),根據(jù)源碼可以得知,我們將其回調(diào)給了handleMessage進(jìn)行事件處理。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
以上就是針對(duì)Handler源碼的一個(gè)簡單的分析,后續(xù)會(huì)對(duì)一些細(xì)節(jié)化的設(shè)計(jì),進(jìn)行專題講解,敬請(qǐng)關(guān)注。