Android應(yīng)用程序是通過消息來驅(qū)動(dòng)的,系統(tǒng)為每一個(gè)應(yīng)用程序維護(hù)一個(gè)消息隊(duì)例,應(yīng)用程序的主線程不斷地從這個(gè)消息隊(duì)例中獲取消息(Looper),然后對(duì)這些消息進(jìn)行處理(Handler),這樣就實(shí)現(xiàn)了通過消息來驅(qū)動(dòng)應(yīng)用程序的執(zhí)行,本文將詳細(xì)分析Android應(yīng)用程序的消息處理機(jī)制。
前面我們學(xué)習(xí)Android應(yīng)用程序中的Activity啟動(dòng)(Android應(yīng)用程序啟動(dòng)過程源代碼分析和Android應(yīng)用程序內(nèi)部啟動(dòng)Activity過程(startActivity)的源代碼分析)、Service啟動(dòng)(Android系統(tǒng)在新進(jìn)程中啟動(dòng)自定義服務(wù)過程(startService)的原理分析和Android應(yīng)用程序綁定服務(wù)(bindService)的過程源代碼分析)以及廣播發(fā)送(Android應(yīng)用程序發(fā)送廣播(sendBroadcast)的過程分析)時(shí),它們都有一個(gè)共同的特點(diǎn),當(dāng)ActivityManagerService需要與應(yīng)用程序進(jìn)行并互時(shí),如加載Activity和Service、處理廣播待,會(huì)通過Binder進(jìn)程間通信機(jī)制來知會(huì)應(yīng)用程序,應(yīng)用程序接收到這個(gè)請(qǐng)求時(shí),它不是馬上就處理這個(gè)請(qǐng)求,而是將這個(gè)請(qǐng)求封裝成一個(gè)消息,然后把這個(gè)消息放在應(yīng)用程序的消息隊(duì)列中去,然后再通過消息循環(huán)來處理這個(gè)消息。這樣做的好處就是消息的發(fā)送方只要把消息發(fā)送到應(yīng)用程序的消息隊(duì)列中去就行了,它可以馬上返回去處理別的事情,而不需要等待消息的接收方去處理完這個(gè)消息才返回,這樣就可以提高系統(tǒng)的并發(fā)性。實(shí)質(zhì)上,這就是一種異步處理機(jī)制。
這樣說可能還是比較籠統(tǒng),我們以Android應(yīng)用程序啟動(dòng)過程源代碼分析一文中所介紹的應(yīng)用程序啟動(dòng)過程的一個(gè)片斷來具體看看是如何這種消息處理機(jī)制的。在這篇文章中,要啟動(dòng)的應(yīng)用程序稱為Activity,它的默認(rèn)Activity是MainActivity,它是由Launcher來負(fù)責(zé)啟動(dòng)的,而Launcher又是通過ActivityManagerService來啟動(dòng)的,當(dāng)ActivityManagerService為這個(gè)即將要啟的應(yīng)用程序準(zhǔn)備好新的進(jìn)程后,便通過一個(gè)Binder進(jìn)程間通信過程來通知這個(gè)新的進(jìn)程來加載MainActivity,如下圖所示:

它對(duì)應(yīng)Android應(yīng)用程序啟動(dòng)過程中的Step 30到Step 35,有興趣的讀者可以回過頭去參考Android應(yīng)用程序啟動(dòng)過程源代碼分析一文。這里的Step 30中的scheduleLaunchActivity是ActivityManagerService通過Binder進(jìn)程間通信機(jī)制發(fā)送過來的請(qǐng)求,它請(qǐng)求應(yīng)用程序中的ActivityThread執(zhí)行Step 34中的performLaunchActivity操作,即啟動(dòng)MainActivity的操作。這里我們就可以看到,Step 30的這個(gè)請(qǐng)求并沒有等待Step 34這個(gè)操作完成就返回了,它只是把這個(gè)請(qǐng)求封裝成一個(gè)消息,然后通過Step 31中的queueOrSendMessage操作把這個(gè)消息放到應(yīng)用程序的消息隊(duì)列中,然后就返回了。應(yīng)用程序發(fā)現(xiàn)消息隊(duì)列中有消息時(shí),就會(huì)通過Step 32中的handleMessage操作來處理這個(gè)消息,即調(diào)用Step 33中的handleLaunchActivity來執(zhí)行實(shí)際的加載MainAcitivy類的操作。
了解Android應(yīng)用程序的消息處理過程之后,我們就開始分樣它的實(shí)現(xiàn)原理了。與Windows應(yīng)用程序的消息處理過程一樣,Android應(yīng)用程序的消息處理機(jī)制也是由消息循環(huán)、消息發(fā)送和消息處理這三個(gè)部分組成的,接下來,我們就詳細(xì)描述這三個(gè)過程。
1. 消息循環(huán)
在消息處理機(jī)制中,消息都是存放在一個(gè)消息隊(duì)列中去,而應(yīng)用程序的主線程就是圍繞這個(gè)消息隊(duì)列進(jìn)入一個(gè)無限循環(huán)的,直到應(yīng)用程序退出。如果隊(duì)列中有消息,應(yīng)用程序的主線程就會(huì)把它取出來,并分發(fā)給相應(yīng)的Handler進(jìn)行處理;如果隊(duì)列中沒有消息,應(yīng)用程序的主線程就會(huì)進(jìn)入空閑等待狀態(tài),等待下一個(gè)消息的到來。在Android應(yīng)用程序中,這個(gè)消息循環(huán)過程是由Looper類來實(shí)現(xiàn)的,它定義在frameworks/base/core/java/android/os/Looper.java文件中,在分析這個(gè)類之前,我們先看一下Android應(yīng)用程序主線程是如何進(jìn)入到這個(gè)消息循環(huán)中去的。
在Android應(yīng)用程序進(jìn)程啟動(dòng)過程的源代碼分析一文中,我們分析了Android應(yīng)用程序進(jìn)程的啟動(dòng)過程,Android應(yīng)用程序進(jìn)程在啟動(dòng)的時(shí)候,會(huì)在進(jìn)程中加載ActivityThread類,并且執(zhí)行這個(gè)類的main函數(shù),應(yīng)用程序的消息循環(huán)過程就是在這個(gè)main函數(shù)里面實(shí)現(xiàn)的,我們來看看這個(gè)函數(shù)的實(shí)現(xiàn),它定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
public final class ActivityThread {
......
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
thread.detach();
......
}
}
這個(gè)函數(shù)做了兩件事情,一是在主線程中創(chuàng)建了一個(gè)ActivityThread實(shí)例,二是通過Looper類使主線程進(jìn)入消息循環(huán)中,這里我們只關(guān)注后者。
首先看Looper.prepareMainLooper函數(shù)的實(shí)現(xiàn),這是一個(gè)靜態(tài)成員函數(shù),定義在frameworks/base/core/java/android/os/Looper.java文件中:
public class Looper {
......
private static final ThreadLocal sThreadLocal = new ThreadLocal();
final MessageQueue mQueue;
......
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
/** Initialize the current thread as a looper, marking it as an application's main
* looper. The main looper for your application is created by the Android environment,
* so you should never need to call this function yourself.
* {@link #prepare()}
*/
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
......
}
函數(shù)prepareMainLooper做的事情其實(shí)就是在線程中創(chuàng)建一個(gè)Looper對(duì)象,這個(gè)Looper對(duì)象是存放在sThreadLocal成員變量里面的,成員變量sThreadLocal的類型為ThreadLocal,表示這是一個(gè)線程局部變量,即保證每一個(gè)調(diào)用了prepareMainLooper函數(shù)的線程里面都有一個(gè)獨(dú)立的Looper對(duì)象。在線程是創(chuàng)建Looper對(duì)象的工作是由prepare函數(shù)來完成的,而在創(chuàng)建Looper對(duì)象的時(shí)候,會(huì)同時(shí)創(chuàng)建一個(gè)消息隊(duì)列MessageQueue,保存在Looper的成員變量mQueue中,后續(xù)消息就是存放在這個(gè)隊(duì)列中去。消息隊(duì)列在Android應(yīng)用程序消息處理機(jī)制中最重要的組件,因此,我們看看它的創(chuàng)建過程,即它的構(gòu)造函數(shù)的實(shí)現(xiàn),實(shí)現(xiàn)frameworks/base/core/java/android/os/MessageQueue.java文件中:
public class MessageQueue {
......
private int mPtr; // used by native code
private native void nativeInit();
MessageQueue() {
nativeInit();
}
......
}
它的初始化工作都交給JNI方法nativeInit來實(shí)現(xiàn)了,這個(gè)JNI方法定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:
static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (! nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return;
}
android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
}
在JNI中,也相應(yīng)地創(chuàng)建了一個(gè)消息隊(duì)列NativeMessageQueue,NativeMessageQueue類也是定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中,它的創(chuàng)建過程如下所示:
NativeMessageQueue::NativeMessageQueue() {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
它主要就是在內(nèi)部創(chuàng)建了一個(gè)Looper對(duì)象,注意,這個(gè)Looper對(duì)象是實(shí)現(xiàn)在JNI層的,它與上面Java層中的Looper是不一樣的,不過它們是對(duì)應(yīng)的,下面我們進(jìn)一步分析消息循環(huán)的過程的時(shí)候,讀者就會(huì)清楚地了解到它們之間的關(guān)系。
這個(gè)Looper的創(chuàng)建過程也很重要,不過我們暫時(shí)放一放,先分析完android_os_MessageQueue_nativeInit函數(shù)的執(zhí)行,它創(chuàng)建了本地消息隊(duì)列NativeMessageQueue對(duì)象之后,接著調(diào)用android_os_MessageQueue_setNativeMessageQueue函數(shù)來把這個(gè)消息隊(duì)列對(duì)象保存在前面我們?cè)贘ava層中創(chuàng)建的MessageQueue對(duì)象的mPtr成員變量里面:
static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject messageQueueObj,
NativeMessageQueue* nativeMessageQueue) {
env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,
reinterpret_cast<jint>(nativeMessageQueue));
}
這里傳進(jìn)來的參數(shù)messageQueueObj即為我們前面在Java層創(chuàng)建的消息隊(duì)列對(duì)象,而gMessageQueueClassInfo.mPtr即表示在Java類MessageQueue中,其成員變量mPtr的偏移量,通過這個(gè)偏移量,就可以把這個(gè)本地消息隊(duì)列對(duì)象natvieMessageQueue保存在Java層創(chuàng)建的消息隊(duì)列對(duì)象的mPtr成員變量中,這是為了后續(xù)我們調(diào)用Java層的消息隊(duì)列對(duì)象的其它成員函數(shù)進(jìn)入到JNI層時(shí),能夠方便地找回它在JNI層所對(duì)應(yīng)的消息隊(duì)列對(duì)象。
我們?cè)倩氐絅ativeMessageQueue的構(gòu)造函數(shù)中,看看JNI層的Looper對(duì)象的創(chuàng)建過程,即看看它的構(gòu)造函數(shù)是如何實(shí)現(xiàn)的,這個(gè)Looper類實(shí)現(xiàn)在frameworks/base/libs/utils/Looper.cpp文件中:
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks),
mResponseIndex(0) {
int wakeFds[2];
int result = pipe(wakeFds);
......
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
......
#ifdef LOOPER_USES_EPOLL
// Allocate the epoll instance and register the wake pipe.
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
......
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
......
#else
......
#endif
......
}
這個(gè)構(gòu)造函數(shù)做的事情非常重要,它跟我們后面要介紹的應(yīng)用程序主線程在消息隊(duì)列中沒有消息時(shí)要進(jìn)入等待狀態(tài)以及當(dāng)消息隊(duì)列有消息時(shí)要把應(yīng)用程序主線程喚醒的這兩個(gè)知識(shí)點(diǎn)息息相關(guān)。它主要就是通過pipe系統(tǒng)調(diào)用來創(chuàng)建了一個(gè)管道了:
int wakeFds[2];
int result = pipe(wakeFds);
......
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
管道是Linux系統(tǒng)中的一種進(jìn)程間通信機(jī)制,具體可以參考前面一篇文章
Android學(xué)習(xí)啟動(dòng)篇推薦的一本書《Linux內(nèi)核源代碼情景分析》中的第6章--傳統(tǒng)的Uinx進(jìn)程間通信。簡(jiǎn)單來說,管道就是一個(gè)文件,在管道的兩端,分別是兩個(gè)打開文件文件描述符,這兩個(gè)打開文件描述符都是對(duì)應(yīng)同一個(gè)文件,其中一個(gè)是用來讀的,別一個(gè)是用來寫的,一般的使用方式就是,一個(gè)線程通過讀文件描述符中來讀管道的內(nèi)容,當(dāng)管道沒有內(nèi)容時(shí),這個(gè)線程就會(huì)進(jìn)入等待狀態(tài),而另外一個(gè)線程通過寫文件描述符來向管道中寫入內(nèi)容,寫入內(nèi)容的時(shí)候,如果另一端正有線程正在等待管道中的內(nèi)容,那么這個(gè)線程就會(huì)被喚醒。這個(gè)等待和喚醒的操作是如何進(jìn)行的呢,這就要借助Linux系統(tǒng)中的epoll機(jī)制了。 Linux系統(tǒng)中的epoll機(jī)制為處理大批量句柄而作了改進(jìn)的poll,是Linux下多路復(fù)用IO接口select/poll的增強(qiáng)版本,它能顯著減少程序在大量并發(fā)連接中只有少量活躍的情況下的系統(tǒng)CPU利用率。但是這里我們其實(shí)只需要監(jiān)控的IO接口只有mWakeReadPipeFd一個(gè),即前面我們所創(chuàng)建的管道的讀端,為什么還需要用到epoll呢?有點(diǎn)用牛刀來殺雞的味道。其實(shí)不然,這個(gè)Looper類是非常強(qiáng)大的,它除了監(jiān)控內(nèi)部所創(chuàng)建的管道接口之外,還提供了addFd接口供外界面調(diào)用,外界可以通過這個(gè)接口把自己想要監(jiān)控的IO事件一并加入到這個(gè)Looper對(duì)象中去,當(dāng)所有這些被監(jiān)控的IO接口上面有事件發(fā)生時(shí),就會(huì)喚醒相應(yīng)的線程來處理,不過這里我們只關(guān)心剛才所創(chuàng)建的管道的IO事件的發(fā)生。
要使用Linux系統(tǒng)的epoll機(jī)制,首先要通過epoll_create來創(chuàng)建一個(gè)epoll專用的文件描述符:
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
傳入的參數(shù)EPOLL_SIZE_HINT是在這個(gè)mEpollFd上能監(jiān)控的最大文件描述符數(shù)。
接著還要通過epoll_ctl函數(shù)來告訴epoll要監(jiān)控相應(yīng)的文件描述符的什么事件:
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
這里就是告訴mEpollFd,它要監(jiān)控mWakeReadPipeFd文件描述符的EPOLLIN事件,即當(dāng)管道中有內(nèi)容可讀時(shí),就喚醒當(dāng)前正在等待管道中的內(nèi)容的線程。
C++層的這個(gè)Looper對(duì)象創(chuàng)建好了之后,就返回到JNI層的NativeMessageQueue的構(gòu)造函數(shù),最后就返回到Java層的消息隊(duì)列MessageQueue的創(chuàng)建過程,這樣,Java層的Looper對(duì)象就準(zhǔn)備好了。有點(diǎn)復(fù)雜,我們先小結(jié)一下這一步都做了些什么事情:
A. 在Java層,創(chuàng)建了一個(gè)Looper對(duì)象,這個(gè)Looper對(duì)象是用來進(jìn)入消息循環(huán)的,它的內(nèi)部有一個(gè)消息隊(duì)列MessageQueue對(duì)象mQueue;
B. 在JNI層,創(chuàng)建了一個(gè)NativeMessageQueue對(duì)象,這個(gè)NativeMessageQueue對(duì)象保存在Java層的消息隊(duì)列對(duì)象mQueue的成員變量mPtr中;
C. 在C++層,創(chuàng)建了一個(gè)Looper對(duì)象,保存在JNI層的NativeMessageQueue對(duì)象的成員變量mLooper中,這個(gè)對(duì)象的作用是,當(dāng)Java層的消息隊(duì)列中沒有消息時(shí),就使Android應(yīng)用程序主線程進(jìn)入等待狀態(tài),而當(dāng)Java層的消息隊(duì)列中來了新的消息后,就喚醒Android應(yīng)用程序的主線程來處理這個(gè)消息。
回到ActivityThread類的main函數(shù)中,在上面這些工作都準(zhǔn)備好之后,就調(diào)用Looper類的loop函數(shù)進(jìn)入到消息循環(huán)中去了:
public class Looper {
......
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
......
while (true) {
Message msg = queue.next(); // might block
......
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
......
msg.target.dispatchMessage(msg);
......
msg.recycle();
}
}
}
......
}
這里就是進(jìn)入到消息循環(huán)中去了,它不斷地從消息隊(duì)列mQueue中去獲取下一個(gè)要處理的消息msg,如果消息的target成員變量為null,就表示要退出消息循環(huán)了,否則的話就要調(diào)用這個(gè)target對(duì)象的dispatchMessage成員函數(shù)來處理這個(gè)消息,這個(gè)target對(duì)象的類型為Handler,下面我們分析消息的發(fā)送時(shí)會(huì)看到這個(gè)消息對(duì)象msg是如設(shè)置的。
這個(gè)函數(shù)最關(guān)鍵的地方便是從消息隊(duì)列中獲取下一個(gè)要處理的消息了,即MessageQueue.next函數(shù),它實(shí)現(xiàn)frameworks/base/core/java/android/os/MessageQueue.java文件中:
public class MessageQueue {
......
final Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
final Message msg = mMessages;
if (msg != null) {
final long when = msg.when;
if (now >= when) {
mBlocked = false;
mMessages = msg.next;
msg.next = null;
if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
} else {
nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
}
} else {
nextPollTimeoutMillis = -1;
}
// If first time, then get the number of idlers to run.
if (pendingIdleHandlerCount < 0) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount == 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// 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;
}
}
......
}
調(diào)用這個(gè)函數(shù)的時(shí)候,有可能會(huì)讓線程進(jìn)入等待狀態(tài)。什么情況下,線程會(huì)進(jìn)入等待狀態(tài)呢??jī)煞N情況,一是當(dāng)消息隊(duì)列中沒有消息時(shí),它會(huì)使線程進(jìn)入等待狀態(tài);二是消息隊(duì)列中有消息,但是消息指定了執(zhí)行的時(shí)間,而現(xiàn)在還沒有到這個(gè)時(shí)間,線程也會(huì)進(jìn)入等待狀態(tài)。消息隊(duì)列中的消息是按時(shí)間先后來排序的,后面我們?cè)诜治鱿⒌陌l(fā)送時(shí)會(huì)看到。
執(zhí)行下面語句是看看當(dāng)前消息隊(duì)列中有沒有消息:
nativePollOnce(mPtr, nextPollTimeoutMillis);
這是一個(gè)JNI方法,我們等一下再分析,這里傳入的參數(shù)mPtr就是指向前面我們?cè)贘NI層創(chuàng)建的NativeMessageQueue對(duì)象了,而參數(shù)nextPollTimeoutMillis則表示如果當(dāng)前消息隊(duì)列中沒有消息,它要等待的時(shí)候,for循環(huán)開始時(shí),傳入的值為0,表示不等待。
當(dāng)前nativePollOnce返回后,就去看看消息隊(duì)列中有沒有消息:
final Message msg = mMessages;
if (msg != null) {
final long when = msg.when;
if (now >= when) {
mBlocked = false;
mMessages = msg.next;
msg.next = null;
if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
} else {
nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
}
} else {
nextPollTimeoutMillis = -1;
}
如果消息隊(duì)列中有消息,并且當(dāng)前時(shí)候大于等于消息中的執(zhí)行時(shí)間,那么就直接返回這個(gè)消息給Looper.loop消息處理,否則的話就要等待到消息的執(zhí)行時(shí)間:
nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
如果消息隊(duì)列中沒有消息,那就要進(jìn)入無窮等待狀態(tài)直到有新消息了:
nextPollTimeoutMillis = -1;
-1表示下次調(diào)用nativePollOnce時(shí),如果消息中沒有消息,就進(jìn)入無限等待狀態(tài)中去。
這里計(jì)算出來的等待時(shí)間都是在下次調(diào)用nativePollOnce時(shí)使用的。
這里說的等待,是空閑等待,而不是忙等待,因此,在進(jìn)入空閑等待狀態(tài)前,如果應(yīng)用程序注冊(cè)了IdleHandler接口來處理一些事情,那么就會(huì)先執(zhí)行這里IdleHandler,然后再進(jìn)入等待狀態(tài)。IdlerHandler是定義在MessageQueue的一個(gè)內(nèi)部類:
public class MessageQueue {
......
/**
* Callback interface for discovering when a thread is going to block
* waiting for more messages.
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now
* wait for more. Return true to keep your idle handler active, false
* to have it removed. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time.
*/
boolean queueIdle();
}
......
}
它只有一個(gè)成員函數(shù)queueIdle,執(zhí)行這個(gè)函數(shù)時(shí),如果返回值為false,那么就會(huì)從應(yīng)用程序中移除這個(gè)IdleHandler,否則的話就會(huì)在應(yīng)用程序中繼續(xù)維護(hù)著這個(gè)IdleHandler,下次空閑時(shí)仍會(huì)再執(zhí)會(huì)這個(gè)IdleHandler。MessageQueue提供了addIdleHandler和removeIdleHandler兩注冊(cè)和刪除IdleHandler。
回到MessageQueue函數(shù)中,它接下來就是在進(jìn)入等待狀態(tài)前,看看有沒有IdleHandler是需要執(zhí)行的:
// If first time, then get the number of idlers to run.
if (pendingIdleHandlerCount < 0) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount == 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
如果沒有,即pendingIdleHandlerCount等于0,那下面的邏輯就不執(zhí)行了,通過continue語句直接進(jìn)入下一次循環(huán),否則就要把注冊(cè)在mIdleHandlers中的IdleHandler取出來,放在mPendingIdleHandlers數(shù)組中去。
接下來就是執(zhí)行這些注冊(cè)了的IdleHanlder了:
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
執(zhí)行完這些IdleHandler之后,線程下次調(diào)用nativePollOnce函數(shù)時(shí),就不設(shè)置超時(shí)時(shí)間了,因?yàn)椋苡锌赡茉趫?zhí)行IdleHandler的時(shí)候,已經(jīng)有新的消息加入到消息隊(duì)列中去了,因此,要重置nextPollTimeoutMillis的值:
// 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;
分析完MessageQueue的這個(gè)next函數(shù)之后,我們就要深入分析一下JNI方法nativePollOnce了,看看它是如何進(jìn)入等待狀態(tài)的,這個(gè)函數(shù)定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jint ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(timeoutMillis);
}
這個(gè)函數(shù)首先是通過傳進(jìn)入的參數(shù)ptr取回前面在Java層創(chuàng)建MessageQueue對(duì)象時(shí)在JNI層創(chuàng)建的NatvieMessageQueue對(duì)象,然后調(diào)用它的pollOnce函數(shù):
void NativeMessageQueue::pollOnce(int timeoutMillis) {
mLooper->pollOnce(timeoutMillis);
}
這里將操作轉(zhuǎn)發(fā)給mLooper對(duì)象的pollOnce函數(shù)處理,這里的mLooper對(duì)象是在C++層的對(duì)象,它也是在前面在JNI層創(chuàng)建的NatvieMessageQueue對(duì)象時(shí)創(chuàng)建的,它的pollOnce函數(shù)定義在frameworks/base/libs/utils/Looper.cpp文件中:
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
......
if (result != 0) {
......
return result;
}
result = pollInner(timeoutMillis);
}
}
為了方便討論,我們把這個(gè)函數(shù)的無關(guān)部分都去掉,它主要就是調(diào)用pollInner函數(shù)來進(jìn)一步操作,如果pollInner返回值不等于0,這個(gè)函數(shù)就可以返回了。
函數(shù)pollInner的定義如下:
int Looper::pollInner(int timeoutMillis) {
......
int result = ALOOPER_POLL_WAKE;
......
#ifdef LOOPER_USES_EPOLL
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
bool acquiredLock = false;
#else
......
#endif
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
LOGW("Poll failed with an unexpected error, errno=%d", errno);
result = ALOOPER_POLL_ERROR;
goto Done;
}
if (eventCount == 0) {
......
result = ALOOPER_POLL_TIMEOUT;
goto Done;
}
......
#ifdef LOOPER_USES_EPOLL
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
}
} else {
......
}
}
if (acquiredLock) {
mLock.unlock();
}
Done: ;
#else
......
#endif
......
return result;
}
這里,首先是調(diào)用epoll_wait函數(shù)來看看epoll專用文件描述符mEpollFd所監(jiān)控的文件描述符是否有IO事件發(fā)生,它設(shè)置監(jiān)控的超時(shí)時(shí)間為timeoutMillis:
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
回憶一下前面的Looper的構(gòu)造函數(shù),我們?cè)诶锩嬖O(shè)置了要監(jiān)控mWakeReadPipeFd文件描述符的EPOLLIN事件。
當(dāng)mEpollFd所監(jiān)控的文件描述符發(fā)生了要監(jiān)控的IO事件后或者監(jiān)控時(shí)間超時(shí)后,線程就從epoll_wait返回了,否則線程就會(huì)在epoll_wait函數(shù)中進(jìn)入睡眠狀態(tài)了。返回后如果eventCount等于0,就說明是超時(shí)了:
if (eventCount == 0) {
......
result = ALOOPER_POLL_TIMEOUT;
goto Done;
}
如果eventCount不等于0,就說明發(fā)生要監(jiān)控的事件:
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
}
} else {
......
}
}
這里我們只關(guān)注mWakeReadPipeFd文件描述符上的事件,如果在mWakeReadPipeFd文件描述符上發(fā)生了EPOLLIN就說明應(yīng)用程序中的消息隊(duì)列里面有新的消息需要處理了,接下來它就會(huì)先調(diào)用awoken函數(shù)清空管道中把內(nèi)容,以便下次再調(diào)用pollInner函數(shù)時(shí),知道自從上次處理完消息隊(duì)列中的消息后,有沒有新的消息加進(jìn)來。
函數(shù)awoken的實(shí)現(xiàn)很簡(jiǎn)單,它只是把管道中的內(nèi)容都讀取出來:
void Looper::awoken() {
......
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
}
因?yàn)楫?dāng)其它的線程向應(yīng)用程序的消息隊(duì)列加入新的消息時(shí),會(huì)向這個(gè)管道寫入新的內(nèi)容來通知應(yīng)用程序主線程有新的消息需要處理了,下面我們分析消息的發(fā)送的時(shí)候?qū)?huì)看到。
這樣,消息的循環(huán)過程就分析完了,這部分邏輯還是比較復(fù)雜的,它利用Linux系統(tǒng)中的管道(pipe)進(jìn)程間通信機(jī)制來實(shí)現(xiàn)消息的等待和處理,不過,了解了這部分內(nèi)容之后,下面我們分析消息的發(fā)送和處理就簡(jiǎn)單多了。
2. 消息的發(fā)送
應(yīng)用程序的主線程準(zhǔn)備就好消息隊(duì)列并且進(jìn)入到消息循環(huán)后,其它地方就可以往這個(gè)消息隊(duì)列中發(fā)送消息了。我們繼續(xù)以文章開始介紹的Android應(yīng)用程序啟動(dòng)過程源代碼分析一文中的應(yīng)用程序啟動(dòng)過為例,說明應(yīng)用程序是如何把消息加入到應(yīng)用程序的消息隊(duì)列中去的。
在Android應(yīng)用程序啟動(dòng)過程源代碼分析這篇文章的Step 30中,ActivityManagerService通過調(diào)用ApplicationThread類的scheduleLaunchActivity函數(shù)通知應(yīng)用程序,它可以加載應(yīng)用程序的默認(rèn)Activity了,這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
public final class ActivityThread {
......
private final class ApplicationThread extends ApplicationThreadNative {
......
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
r.state = state;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
......
}
......
}
這里把相關(guān)的參數(shù)都封裝成一個(gè)ActivityClientRecord對(duì)象r,然后調(diào)用queueOrSendMessage函數(shù)來往應(yīng)用程序的消息隊(duì)列中加入一個(gè)新的消息(H.LAUNCH_ACTIVITY),這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
public final class ActivityThread {
......
private final class ApplicationThread extends ApplicationThreadNative {
......
// if the thread hasn't started yet, we don't have the handler, so just
// save the messages until we're ready.
private final void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, obj, 0, 0);
}
......
private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg);
}
}
......
}
......
}
在queueOrSendMessage函數(shù)中,又進(jìn)一步把上面?zhèn)鬟M(jìn)來的參數(shù)封裝成一個(gè)Message對(duì)象msg,然后通過mH.sendMessage函數(shù)把這個(gè)消息對(duì)象msg加入到應(yīng)用程序的消息隊(duì)列中去。這里的mH是ActivityThread類的成員變量,它的類型為H,繼承于Handler類,它定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
public final class ActivityThread {
......
private final class H extends Handler {
......
public void handleMessage(Message msg) {
......
switch (msg.what) {
......
}
......
}
......
}
這個(gè)H類就是通過其成員函數(shù)handleMessage函數(shù)來處理消息的了,后面我們分析消息的處理過程時(shí)會(huì)看到。
ActivityThread類的這個(gè)mH成員變量是什么時(shí)候創(chuàng)建的呢?我們前面在分析應(yīng)用程序的消息循環(huán)時(shí),說到當(dāng)應(yīng)用程序進(jìn)程啟動(dòng)之后,就會(huì)加載ActivityThread類的main函數(shù)里面,在這個(gè)main函數(shù)里面,在通過Looper類進(jìn)入消息循環(huán)之前,會(huì)在當(dāng)前進(jìn)程中創(chuàng)建一個(gè)ActivityThread實(shí)例:
public final class ActivityThread {
......
public static final void main(String[] args) {
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
}
}
在創(chuàng)建這個(gè)實(shí)例的時(shí)候,就會(huì)同時(shí)創(chuàng)建其成員變量mH了:
public final class ActivityThread {
......
final H mH = new H();
......
}
前面說過,H類繼承于Handler類,因此,當(dāng)創(chuàng)建這個(gè)H對(duì)象時(shí),會(huì)調(diào)用Handler類的構(gòu)造函數(shù),這個(gè)函數(shù)定義在frameworks/base/core/java/android/os/Handler.java文件中:
public class Handler {
......
public Handler() {
......
mLooper = Looper.myLooper();
......
mQueue = mLooper.mQueue;
......
}
final MessageQueue mQueue;
final Looper mLooper;
......
}
在Hanlder類的構(gòu)造函數(shù)中,主要就是初始成員變量mLooper和mQueue了。這里的myLooper是Looper類的靜態(tài)成員函數(shù),通過它來獲得一個(gè)Looper對(duì)象,這個(gè)Looper對(duì)象就是前面我們?cè)诜治鱿⒀h(huán)時(shí),在ActivityThread類的main函數(shù)中通過Looper.prepareMainLooper函數(shù)創(chuàng)建的。Looper.myLooper函數(shù)實(shí)現(xiàn)在frameworks/base/core/java/android/os/Looper.java文件中:
public class Looper {
......
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
......
}
有了這個(gè)Looper對(duì)象后,就可以通過Looper.mQueue來訪問應(yīng)用程序的消息隊(duì)列了。
有了這個(gè)Handler對(duì)象mH后,就可以通過它來往應(yīng)用程序的消息隊(duì)列中加入新的消息了。回到前面的queueOrSendMessage函數(shù)中,當(dāng)它準(zhǔn)備好了一個(gè)Message對(duì)象msg后,就開始調(diào)用mH.sendMessage函數(shù)來發(fā)送消息了,這個(gè)函數(shù)定義在frameworks/base/core/java/android/os/Handler.java文件中:
public class Handler {
......
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)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
......
}
return sent;
}
......
}
在發(fā)送消息時(shí),是可以指定消息的處理時(shí)間的,但是通過sendMessage函數(shù)發(fā)送的消息的處理時(shí)間默認(rèn)就為當(dāng)前時(shí)間,即表示要馬上處理,因此,從sendMessage函數(shù)中調(diào)用sendMessageDelayed函數(shù),傳入的時(shí)間參數(shù)為0,表示這個(gè)消息不要延時(shí)處理,而在sendMessageDelayed函數(shù)中,則會(huì)先獲得當(dāng)前時(shí)間,然后加上消息要延時(shí)處理的時(shí)間,即得到這個(gè)處理這個(gè)消息的絕對(duì)時(shí)間,然后調(diào)用sendMessageAtTime函數(shù)來把消息加入到應(yīng)用程序的消息隊(duì)列中去。
在sendMessageAtTime函數(shù),首先得到應(yīng)用程序的消息隊(duì)列mQueue,這是在Handler對(duì)象構(gòu)造時(shí)初始化好的,前面已經(jīng)分析過了,接著設(shè)置這個(gè)消息的目標(biāo)對(duì)象target,即這個(gè)消息最終是由誰來處理的:
msg.target = this;
這里將它賦值為this,即表示這個(gè)消息最終由這個(gè)Handler對(duì)象來處理,即由ActivityThread對(duì)象的mH成員變量來處理。
函數(shù)最后調(diào)用queue.enqueueMessage來把這個(gè)消息加入到應(yīng)用程序的消息隊(duì)列中去,這個(gè)函數(shù)實(shí)現(xiàn)在frameworks/base/core/java/android/os/MessageQueue.java文件中:
public class MessageQueue {
......
final boolean enqueueMessage(Message msg, long when) {
......
final boolean needWake;
synchronized (this) {
......
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
......
}
把消息加入到消息隊(duì)列時(shí),分兩種情況,一種當(dāng)前消息隊(duì)列為空時(shí),這時(shí)候應(yīng)用程序的主線程一般就是處于空閑等待狀態(tài)了,這時(shí)候就要喚醒它,另一種情況是應(yīng)用程序的消息隊(duì)列不為空,這時(shí)候就不需要喚醒應(yīng)用程序的主線程了,因?yàn)檫@時(shí)候它一定是在忙著處于消息隊(duì)列中的消息,因此不會(huì)處于空閑等待的狀態(tài)。
第一種情況比較簡(jiǎn)單,只要把消息放在消息隊(duì)列頭就可以了:
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
第二種情況相對(duì)就比較復(fù)雜一些了,前面我們說過,當(dāng)往消息隊(duì)列中發(fā)送消息時(shí),是可以指定消息的處理時(shí)間的,而消息隊(duì)列中的消息,就是按照這個(gè)時(shí)間從小到大來排序的,因此,當(dāng)把新的消息加入到消息隊(duì)列時(shí),就要根據(jù)它的處理時(shí)間來找到合適的位置,然后再放進(jìn)消息隊(duì)列中去:
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
把消息加入到消息隊(duì)列去后,如果應(yīng)用程序的主線程正處于空閑等待狀態(tài),就需要調(diào)用natvieWake函數(shù)來喚醒它了,這是一個(gè)JNI方法,定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
return nativeMessageQueue->wake();
}
這個(gè)JNI層的NativeMessageQueue對(duì)象我們?cè)谇懊娣治鱿⒀h(huán)的時(shí)候創(chuàng)建好的,保存在Java層的MessageQueue對(duì)象的mPtr成員變量中,這里把它取回來之后,就調(diào)用它的wake函數(shù)來喚醒應(yīng)用程序的主線程,這個(gè)函數(shù)也是定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:
void NativeMessageQueue::wake() {
mLooper->wake();
}
這里它又通過成員變量mLooper的wake函數(shù)來執(zhí)行操作,這里的mLooper成員變量是一個(gè)C++層實(shí)現(xiàn)的Looper對(duì)象,它定義在frameworks/base/libs/utils/Looper.cpp文件中:
void Looper::wake() {
......
ssize_t nWrite;
do {
nWrite = write(mWakeWritePipeFd, "W", 1);
} while (nWrite == -1 && errno == EINTR);
.......
}
這個(gè)wake函數(shù)很簡(jiǎn)單,只是通過打開文件描述符mWakeWritePipeFd往管道的寫入一個(gè)"W"字符串。其實(shí),往管道寫入什么內(nèi)容并不重要,往管道寫入內(nèi)容的目的是為了喚醒應(yīng)用程序的主線程。前面我們?cè)诜治鰬?yīng)用程序的消息循環(huán)時(shí)說到,當(dāng)應(yīng)用程序的消息隊(duì)列中沒有消息處理時(shí),應(yīng)用程序的主線程就會(huì)進(jìn)入空閑等待狀態(tài),而這個(gè)空閑等待狀態(tài)就是通過調(diào)用這個(gè)Looper類的pollInner函數(shù)來進(jìn)入的,具體就是在pollInner函數(shù)中調(diào)用epoll_wait函數(shù)來等待管道中有內(nèi)容可讀的。
這時(shí)候既然管道中有內(nèi)容可讀了,應(yīng)用程序的主線程就會(huì)從這里的Looper類的pollInner函數(shù)返回到JNI層的nativePollOnce函數(shù),最后返回到Java層中的MessageQueue.next函數(shù)中去,這里它就會(huì)發(fā)現(xiàn)消息隊(duì)列中有新的消息需要處理了,于就會(huì)處理這個(gè)消息。
3. 消息的處理
前面在分析消息循環(huán)時(shí),說到應(yīng)用程序的主線程是在Looper類的loop成員函數(shù)中進(jìn)行消息循環(huán)過程的,這個(gè)函數(shù)定義在frameworks/base/core/java/android/os/Looper.java文件中:
public class Looper {
......
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
......
while (true) {
Message msg = queue.next(); // might block
......
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
......
msg.target.dispatchMessage(msg);
......
msg.recycle();
}
}
}
......
}
它從消息隊(duì)列中獲得消息對(duì)象msg后,就會(huì)調(diào)用它的target成員變量的dispatchMessage函數(shù)來處理這個(gè)消息。在前面分析消息的發(fā)送時(shí)說過,這個(gè)消息對(duì)象msg的成員變量target是在發(fā)送消息的時(shí)候設(shè)置好的,一般就通過哪個(gè)Handler來發(fā)送消息,就通過哪個(gè)Handler來處理消息。
我們繼續(xù)以前面分析消息的發(fā)送時(shí)所舉的例子來分析消息的處理過程。前面說到,在Android應(yīng)用程序啟動(dòng)過程源代碼分析這篇文章的Step 30中,ActivityManagerService通過調(diào)用ApplicationThread類的scheduleLaunchActivity函數(shù)通知應(yīng)用程序,它可以加載應(yīng)用程序的默認(rèn)Activity了,而ApplicationThread類的scheduleLaunchActivity函數(shù)最終把這個(gè)請(qǐng)求封裝成一個(gè)消息,然后通過ActivityThread類的成員變量mH來把這個(gè)消息加入到應(yīng)用程序的消息隊(duì)列中去。現(xiàn)在要對(duì)這個(gè)消息進(jìn)行處理了,于是就會(huì)調(diào)用H類的dispatchMessage函數(shù)進(jìn)行處理。
H類沒有實(shí)現(xiàn)自己的dispatchMessage函數(shù),但是它繼承了父類Handler的dispatchMessage函數(shù),這個(gè)函數(shù)定義在frameworks/base/core/java/android/os/ Handler.java文件中:
public class Handler {
......
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
......
}
這里的消息對(duì)象msg的callback成員變量和Handler類的mCallBack成員變量一般都為null,于是,就會(huì)調(diào)用Handler類的handleMessage函數(shù)來處理這個(gè)消息,由于H類在繼承Handler類時(shí),重寫了handleMessage函數(shù),因此,這里調(diào)用的實(shí)際上是H類的handleMessage函數(shù),這個(gè)函數(shù)定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
public final class ActivityThread {
......
private final class H extends Handler {
......
public void handleMessage(Message msg) {
......
switch (msg.what) {
case LAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo);
handleLaunchActivity(r, null);
} break;
......
}
......
}
......
}
因?yàn)榍懊嬖诜治鱿⒌陌l(fā)送時(shí)所舉的例子中,發(fā)送的消息的類型為H.LAUNCH_ACTIVITY,因此,這里就會(huì)調(diào)用ActivityThread類的handleLaunchActivity函數(shù)來真正地處理這個(gè)消息了,后面的具體過程就可以參考
Android應(yīng)用程序啟動(dòng)過程源代碼分析這篇文章了。
至此,我們就從消息循環(huán)、消息發(fā)送和消息處理三個(gè)部分分析完Android應(yīng)用程序的消息處理機(jī)制了,為了更深理解,這里我們對(duì)其中的一些要點(diǎn)作一個(gè)總結(jié):
A. Android應(yīng)用程序的消息處理機(jī)制由消息循環(huán)、消息發(fā)送和消息處理三個(gè)部分組成的。
B. Android應(yīng)用程序的主線程在進(jìn)入消息循環(huán)過程前,會(huì)在內(nèi)部創(chuàng)建一個(gè)Linux管道(Pipe),這個(gè)管道的作用是使得Android應(yīng)用程序主線程在消息隊(duì)列為空時(shí)可以進(jìn)入空閑等待狀態(tài),并且使得當(dāng)應(yīng)用程序的消息隊(duì)列有消息需要處理時(shí)喚醒應(yīng)用程序的主線程。
C. Android應(yīng)用程序的主線程進(jìn)入空閑等待狀態(tài)的方式實(shí)際上就是在管道的讀端等待管道中有新的內(nèi)容可讀,具體來說就是是通過Linux系統(tǒng)的Epoll機(jī)制中的epoll_wait函數(shù)進(jìn)行的。
D. 當(dāng)往Android應(yīng)用程序的消息隊(duì)列中加入新的消息時(shí),會(huì)同時(shí)往管道中的寫端寫入內(nèi)容,通過這種方式就可以喚醒正在等待消息到來的應(yīng)用程序主線程。
E. 當(dāng)應(yīng)用程序主線程在進(jìn)入空閑等待前,會(huì)認(rèn)為當(dāng)前線程處理空閑狀態(tài),于是就會(huì)調(diào)用那些已經(jīng)注冊(cè)了的IdleHandler接口,使得應(yīng)用程序有機(jī)會(huì)在空閑的時(shí)候處理一些事情。
作者:Luoshengyang 發(fā)表于2011-9-29 0:58:04
原文鏈接
posted on 2012-04-17 21:32
mixer-a 閱讀(1434)
評(píng)論(1) 編輯 收藏