說(shuō)明:本文是基于Android6.0源碼來(lái)分析的
- 這片文章主要是從源碼的角度來(lái)分析Android中的消息機(jī)制是如何運(yùn)行的,并不會(huì)介紹如何使用Handler。
- Android的消息機(jī)制可以說(shuō)是Android的血液,流淌在不同的app之間,催動(dòng)這各種事件有序的執(zhí)行。
- Android進(jìn)程在啟動(dòng)的時(shí)候會(huì)調(diào)用ThreadActivity的main方法,從main方法中我們可以看出,Android的app進(jìn)程啟動(dòng)以后只有一個(gè)線程ActivityThread他是main線程,除了創(chuàng)建主線程方法以外,還為我們的主線程準(zhǔn)備了mianLooper,最后開(kāi)啟了一個(gè)Looper 循環(huán)
整個(gè)消息機(jī)制的一個(gè)重要用途,就是線程間通信,而且大部分都是工作線程向主線程發(fā)送數(shù)據(jù)和消息。那么為什么Android系統(tǒng)要這樣設(shè)計(jì)呢?其實(shí)典型的Android應(yīng)用,都是事件驅(qū)動(dòng)的GUI程序,跟Window的GUI程序很類似。這種程序,特點(diǎn)就是基于事件運(yùn)行,比如點(diǎn)擊事件或者滑動(dòng)事件。所以這種情況下,肯定是要有一個(gè)專門的線程來(lái)負(fù)責(zé)事件的監(jiān)聽(tīng)和分發(fā)。在Android中,系統(tǒng)默認(rèn)啟動(dòng)的主線程,就干這個(gè)事情了。
由于該消息分發(fā)線程有著自己獨(dú)特的任務(wù),所以如果該線程阻塞了的話,系統(tǒng)就會(huì)出現(xiàn)無(wú)響應(yīng)的情況。這樣,自然就不可能把耗時(shí)的任務(wù)放在該線程中,所以官方推薦是把耗時(shí)的任務(wù)放到工作線程中執(zhí)行。但是很多時(shí)候,耗時(shí)任務(wù)的執(zhí)行結(jié)果,都是要反饋到UI上的。而Android中的View,是不能在非UI線程中更新的,因?yàn)閂iew不是線程安全的,沒(méi)有同步,所以必須要把數(shù)據(jù)通過(guò)線程間通信的模式,發(fā)送到UI線程,這能才可以正常更新UI。
所以大家會(huì)問(wèn),Android為什么不把View設(shè)計(jì)成線程安全的呢?那么在Java這種指令式編程語(yǔ)言中,線程安全就是意味著要加鎖。其實(shí)我們可以思考一下,整個(gè)View響應(yīng)事件,事件從屏幕產(chǎn)生,經(jīng)過(guò)Framework,最后到kernel,然后kernel處理完成后,向上傳遞到framework,然后又傳遞到View層。如下圖所示:
那么如果整個(gè)流程都是線程安全的話,就會(huì)面臨著兩個(gè)相對(duì)的加鎖流程,這種反方向的加鎖,很容易就會(huì)導(dǎo)致死鎖的情況發(fā)生。這是絕大多數(shù)GUI系統(tǒng)存在的問(wèn)題,所以絕大多數(shù)GUI系統(tǒng)都是采用事件分發(fā)機(jī)制來(lái)實(shí)現(xiàn)的。所以說(shuō)Android為什么設(shè)計(jì)成單線程模型了。
參考博客: Android消息機(jī)制探索(Handler,Looper,Message,MessageQueue)
public static void main(String[] args) {
...
//為主線程準(zhǔn)備一個(gè)loop
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
//開(kāi)啟消息循環(huán)。
Looper.loop();
...
}
prepareMainLooper方法主要是準(zhǔn)備Lopper,里面還掉用了 prepare(false);方法,注意一下參數(shù),傳的是false,也就是不允許主線程的loop推出;如果我們?cè)谧约簞?chuàng)建的線程去創(chuàng)建looper的以后,我們這里傳的就是true了。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//我們自己創(chuàng)建的線程準(zhǔn)備looper的時(shí)候,會(huì)調(diào)用這個(gè)方法,可以看到傳了false。
public static void prepare() {
prepare(true);
}
接下來(lái)我們分析一下loop()方法。looper方法是一個(gè)無(wú)限循環(huán)的方法,不斷去消息隊(duì)列里取出消息發(fā)送給對(duì)一個(gè)的Handler處理。
public static void loop() {
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;
// 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 long ident = Binder.clearCallingIdentity();
for (;;) {
//取出一個(gè)消息處理,
Message msg = queue.next(); // might block
if (msg == null) {
//沒(méi)有消息了就退出消息循環(huán)。
// No message indicates that the message queue is quitting.
return;
}
//把消息分發(fā)給對(duì)應(yīng)的handler處理。
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
//把已經(jīng)處理的消息放回到消息池里面,用來(lái)復(fù)用這個(gè)消息。這個(gè)消息吃的最大緩存熟是50。
msg.recycleUnchecked();
}
}
那么消息隊(duì)列是在什么時(shí)候創(chuàng)建的呢?其實(shí)是在為每個(gè)線程準(zhǔn)備Lopper的時(shí)候創(chuàng)建的,是在Looper的構(gòu)造函數(shù)里
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
從上面的邏輯我們可以看出,每個(gè)Looper的創(chuàng)建都會(huì)伴隨著一個(gè)消息隊(duì)列的產(chǎn)生,也就是不同線程之間的消息隊(duì)列是不一樣的,每個(gè)線程都會(huì)創(chuàng)建一個(gè)消息隊(duì)列。另外looper里面的一個(gè)成員sThreadLocal,這個(gè)是ThreadLocal類型的,ThreadLocal這個(gè)類會(huì)單獨(dú)為每個(gè)線程存儲(chǔ)一個(gè)本線程單獨(dú)使用的Looper,線程之間不會(huì)共享,也不會(huì)相互干擾。
- 消息循環(huán)我們就分析完了,接下來(lái)我們分析消息是怎么分發(fā)到消息隊(duì)列里的
- 消息的分發(fā)是通過(guò)下面這樣的方式發(fā)送出去的。
Handler mHandler = new Handler(Looper.getMainLooper());
Message msg = Message.obtain()
給消息中添加參數(shù)的標(biāo)識(shí)。
msg.what = 1;//這個(gè)消息的標(biāo)識(shí)
msg.ars1 = 2;//這個(gè)消息鎖攜帶的數(shù)據(jù)
mHandler.sendMessage(msg) //發(fā)送消息
可以看出,發(fā)送消息需要一個(gè)消息載體Message和運(yùn)送載體的Handler
- 我們來(lái)分析一下Handler的構(gòu)造函數(shù)
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
//這里為我們自定義Handler給出來(lái)知道方針,不推薦匿名內(nèi)部類,成員類局部累;如果非要在一個(gè)類的內(nèi)部使用,最好就是靜態(tài)的內(nèi)部類。
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//這個(gè)地方拋出的異常我們應(yīng)該很熟悉類,就是在我們自己創(chuàng)建的子線程里面用消息機(jī)制的時(shí)候沒(méi)有調(diào)用Looper.prepare()發(fā)導(dǎo)致的
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//拿到當(dāng)前l(fā)oop擁有的handler
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//為該message指定處理這個(gè)消息的handler,后面在處理這個(gè)消息的時(shí)候
//就是在循環(huán)中拿到這個(gè)handler去處理這個(gè)消息,所以這一步很重要。
msg.target = this;
//由于我們分析的是無(wú)參數(shù)的構(gòu)造mAsynchronous=false
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//消息入隊(duì)列
return queue.enqueueMessage(msg, uptimeMillis);
}
enqueueMessage有兩個(gè)操作,一個(gè)是沒(méi)有隊(duì)列的時(shí)候構(gòu)造隊(duì)列的頭,另外一個(gè)就是入隊(duì)操作。
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) {
//沒(méi)有隊(duì)列,創(chuàng)建隊(duì)列的頭
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 根據(jù)msg.when的先后,找到合適的插入位置,先執(zhí)行的在隊(duì)列前面;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//隊(duì)列存在,入隊(duì)操作,其實(shí)就是單鏈表的插入操作。
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;
}
消息的入隊(duì)操作介紹完來(lái),下面介紹消息是什么時(shí)候分發(fā)給處理者的
還記得我們的消息的哪個(gè)無(wú)限的for循環(huán)嗎,我再貼一下代碼
for (;;) {
//取出一個(gè)消息處理,
Message msg = queue.next(); // might block
if (msg == null) {
//沒(méi)有消息了就推出消息循環(huán)。
// No message indicates that the message queue is quitting.
return;
}
//把消息分發(fā)給對(duì)應(yīng)的handler處理。
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
//把已經(jīng)處理的消息放回到消息池里面,用來(lái)復(fù)用這個(gè)消息。這個(gè)消息吃的最大緩存熟是50。
msg.recycleUnchecked();
}
msg.target.dispatchMessage(msg);這一行就是去把消息分發(fā)給對(duì)應(yīng)的handler處理
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
dispatchMessage分發(fā)最終把消息傳給來(lái)handlerMessage分發(fā),所以我們?cè)趧?chuàng)建Handler的時(shí)候都要復(fù)寫handlerMessage方法來(lái)處理分發(fā)過(guò)來(lái)的消息;因?yàn)槲覀冇玫氖菬o(wú)參數(shù)的
Handler的構(gòu)造分發(fā),所以mCallback是null,但是如果我們傳來(lái)mCallback,可以看到回調(diào)函數(shù)的優(yōu)先級(jí)是比handlerMessage分發(fā)的優(yōu)先級(jí)高的。
Android的消息機(jī)制我們就介紹完來(lái),下面我們總結(jié)一下:
- 涉及到的類有:
- Looper:主要用來(lái)創(chuàng)建消息隊(duì)列和對(duì)消息隊(duì)列進(jìn)行遍歷
- MessageQueue:主要用來(lái)存儲(chǔ)Handler發(fā)過(guò)來(lái)的消息
- Message:消息的載體,主要負(fù)責(zé)攜帶我們發(fā)送的數(shù)據(jù)
- Handler:消息的發(fā)送者和執(zhí)行者。
