Android應用程式訊息處理機制(Looper、Handler)分析
Android應用程式是通過訊息來驅動的,系統為每一個應用程式維護一個訊息隊例,應用程式的主執行緒不斷地從這個訊息隊例中獲取訊息(Looper),然後對這些訊息進行處理(Handler),這樣就實現了通過訊息來驅動應用程式的執行,本文將詳細分析Android應用程式的訊息處理機制。
前面我們學習Android應用程式中的Activity啟動(Android應用程式啟動過程原始碼分析和Android應用程式內部啟動Activity過程(startActivity)的原始碼分析)、Service啟動(Android系統在新程式中啟動自定義服務過程(startService)的原理分析和Android應用程式繫結服務(bindService)的過程原始碼分析)以及廣播傳送(Android應用程式傳送廣播(sendBroadcast)的過程分析)時,它們都有一個共同的特點,當ActivityManagerService需要與應用程式進行並互時,如載入Activity和Service、處理廣播待,會通過Binder程式間通訊機制來知會應用程式,應用程式接收到這個請求時,它不是馬上就處理這個請求,而是將這個請求封裝成一個訊息,然後把這個訊息放在應用程式的訊息佇列中去,然後再通過訊息迴圈來處理這個訊息。這樣做的好處就是訊息的傳送方只要把訊息傳送到應用程式的訊息佇列中去就行了,它可以馬上返回去處理別的事情,而不需要等待訊息的接收方去處理完這個訊息才返回,這樣就可以提高系統的併發性。實質上,這就是一種非同步處理機制。
這樣說可能還是比較籠統,我們以Android應用程式啟動過程原始碼分析一文中所介紹的應用程式啟動過程的一個片斷來具體看看是如何這種訊息處理機制的。在這篇文章中,要啟動的應用程式稱為Activity,它的預設Activity是MainActivity,它是由Launcher來負責啟動的,而Launcher又是通過ActivityManagerService來啟動的,當ActivityManagerService為這個即將要啟的應用程式準備好新的程式後,便通過一個Binder程式間通訊過程來通知這個新的程式來載入MainActivity,如下圖所示:
它對應Android應用程式啟動過程中的Step 30到Step 35,有興趣的讀者可以回過頭去參考Android應用程式啟動過程原始碼分析一文。這裡的Step 30中的scheduleLaunchActivity是ActivityManagerService通過Binder程式間通訊機制傳送過來的請求,它請求應用程式中的ActivityThread執行Step 34中的performLaunchActivity操作,即啟動MainActivity的操作。這裡我們就可以看到,Step 30的這個請求並沒有等待Step 34這個操作完成就返回了,它只是把這個請求封裝成一個訊息,然後通過Step 31中的queueOrSendMessage操作把這個訊息放到應用程式的訊息佇列中,然後就返回了。應用程式發現訊息佇列中有訊息時,就會通過Step 32中的handleMessage操作來處理這個訊息,即呼叫Step 33中的handleLaunchActivity來執行實際的載入MainAcitivy類的操作。
瞭解Android應用程式的訊息處理過程之後,我們就開始分樣它的實現原理了。與Windows應用程式的訊息處理過程一樣,Android應用程式的訊息處理機制也是由訊息迴圈、訊息傳送和訊息處理這三個部分組成的,接下來,我們就詳細描述這三個過程。
1. 訊息迴圈
在訊息處理機制中,訊息都是存放在一個訊息佇列中去,而應用程式的主執行緒就是圍繞這個訊息佇列進入一個無限迴圈的,直到應用程式退出。如果佇列中有訊息,應用程式的主執行緒就會把它取出來,並分發給相應的Handler進行處理;如果佇列中沒有訊息,應用程式的主執行緒就會進入空閒等待狀態,等待下一個訊息的到來。在Android應用程式中,這個訊息迴圈過程是由Looper類來實現的,它定義在frameworks/base/core/java/android/os/Looper.java檔案中,在分析這個類之前,我們先看一下Android應用程式主執行緒是如何進入到這個訊息迴圈中去的。
在Android應用程式程式啟動過程的原始碼分析一文中,我們分析了Android應用程式程式的啟動過程,Android應用程式程式在啟動的時候,會在程式中載入ActivityThread類,並且執行這個類的main函式,應用程式的訊息迴圈過程就是在這個main函式裡面實現的,我們來看看這個函式的實現,它定義在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();
- ......
- }
- }
首先看Looper.prepareMainLooper函式的實現,這是一個靜態成員函式,定義在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();
- }
- ......
- }
- public class MessageQueue {
- ......
- private int mPtr; // used by native code
- private native void nativeInit();
- MessageQueue() {
- nativeInit();
- }
- ......
- }
- 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);
- }
- NativeMessageQueue::NativeMessageQueue() {
- mLooper = Looper::getForThread();
- if (mLooper == NULL) {
- mLooper = new Looper(false);
- Looper::setForThread(mLooper);
- }
- }
這個Looper的建立過程也很重要,不過我們暫時放一放,先分析完android_os_MessageQueue_nativeInit函式的執行,它建立了本地訊息佇列NativeMessageQueue物件之後,接著呼叫android_os_MessageQueue_setNativeMessageQueue函式來把這個訊息佇列物件儲存在前面我們在Java層中建立的MessageQueue物件的mPtr成員變數裡面:
- static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject messageQueueObj,
- NativeMessageQueue* nativeMessageQueue) {
- env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,
- reinterpret_cast<jint>(nativeMessageQueue));
- }
我們再回到NativeMessageQueue的建構函式中,看看JNI層的Looper物件的建立過程,即看看它的建構函式是如何實現的,這個Looper類實現在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
- ......
- }
- int wakeFds[2];
- int result = pipe(wakeFds);
- ......
- mWakeReadPipeFd = wakeFds[0];
- mWakeWritePipeFd = wakeFds[1];
要使用Linux系統的epoll機制,首先要通過epoll_create來建立一個epoll專用的檔案描述符:
- mEpollFd = epoll_create(EPOLL_SIZE_HINT);
接著還要通過epoll_ctl函式來告訴epoll要監控相應的檔案描述符的什麼事件:
- 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);
C++層的這個Looper物件建立好了之後,就返回到JNI層的NativeMessageQueue的建構函式,最後就返回到Java層的訊息佇列MessageQueue的建立過程,這樣,Java層的Looper物件就準備好了。有點複雜,我們先小結一下這一步都做了些什麼事情:
A. 在Java層,建立了一個Looper物件,這個Looper物件是用來進入訊息迴圈的,它的內部有一個訊息佇列MessageQueue物件mQueue;
B. 在JNI層,建立了一個NativeMessageQueue物件,這個NativeMessageQueue物件儲存在Java層的訊息佇列物件mQueue的成員變數mPtr中;
C. 在C++層,建立了一個Looper物件,儲存在JNI層的NativeMessageQueue物件的成員變數mLooper中,這個物件的作用是,當Java層的訊息佇列中沒有訊息時,就使Android應用程式主執行緒進入等待狀態,而當Java層的訊息佇列中來了新的訊息後,就喚醒Android應用程式的主執行緒來處理這個訊息。
回到ActivityThread類的main函式中,在上面這些工作都準備好之後,就呼叫Looper類的loop函式進入到訊息迴圈中去了:
- 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();
- }
- }
- }
- ......
- }
這個函式最關鍵的地方便是從訊息佇列中獲取下一個要處理的訊息了,即MessageQueue.next函式,它實現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;
- }
- }
- ......
- }
執行下面語句是看看當前訊息佇列中有沒有訊息:
- nativePollOnce(mPtr, nextPollTimeoutMillis);
當前nativePollOnce返回後,就去看看訊息佇列中有沒有訊息:
- 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;
- }
- nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
- nextPollTimeoutMillis = -1;
這裡計算出來的等待時間都是在下次呼叫nativePollOnce時使用的。
這裡說的等待,是空閒等待,而不是忙等待,因此,在進入空閒等待狀態前,如果應用程式註冊了IdleHandler介面來處理一些事情,那麼就會先執行這裡IdleHandler,然後再進入等待狀態。IdlerHandler是定義在MessageQueue的一個內部類:
- 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();
- }
- ......
- }
回到MessageQueue函式中,它接下來就是在進入等待狀態前,看看有沒有IdleHandler是需要執行的:
- // 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);
接下來就是執行這些註冊了的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);
- }
- }
- }
- // 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;
- static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
- jint ptr, jint timeoutMillis) {
- NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
- nativeMessageQueue->pollOnce(timeoutMillis);
- }
- void NativeMessageQueue::pollOnce(int timeoutMillis) {
- mLooper->pollOnce(timeoutMillis);
- }
- int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
- int result = 0;
- for (;;) {
- ......
- if (result != 0) {
- ......
- return result;
- }
- result = pollInner(timeoutMillis);
- }
- }
函式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;
- }
- int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
當mEpollFd所監控的檔案描述符發生了要監控的IO事件後或者監控時間超時後,執行緒就從epoll_wait返回了,否則執行緒就會在epoll_wait函式中進入睡眠狀態了。返回後如果eventCount等於0,就說明是超時了:
- if (eventCount == 0) {
- ......
- result = ALOOPER_POLL_TIMEOUT;
- goto Done;
- }
- 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 {
- ......
- }
- }
函式awoken的實現很簡單,它只是把管道中的內容都讀取出來:
- void Looper::awoken() {
- ......
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
- }
這樣,訊息的迴圈過程就分析完了,這部分邏輯還是比較複雜的,它利用Linux系統中的管道(pipe)程式間通訊機制來實現訊息的等待和處理,不過,瞭解了這部分內容之後,下面我們分析訊息的傳送和處理就簡單多了。
2. 訊息的傳送
應用程式的主執行緒準備就好訊息佇列並且進入到訊息迴圈後,其它地方就可以往這個訊息佇列中傳送訊息了。我們繼續以文章開始介紹的Android應用程式啟動過程原始碼分析一文中的應用程式啟動過為例,說明應用程式是如何把訊息加入到應用程式的訊息佇列中去的。
在Android應用程式啟動過程原始碼分析這篇文章的Step 30中,ActivityManagerService通過呼叫ApplicationThread類的scheduleLaunchActivity函式通知應用程式,它可以載入應用程式的預設Activity了,這個函式定義在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);
- }
- ......
- }
- ......
- }
- 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);
- }
- }
- ......
- }
- ......
- }
- public final class ActivityThread {
- ......
- private final class H extends Handler {
- ......
- public void handleMessage(Message msg) {
- ......
- switch (msg.what) {
- ......
- }
- ......
- }
- ......
- }
這個H類就是通過其成員函式handleMessage函式來處理訊息的了,後面我們分析訊息的處理過程時會看到。
ActivityThread類的這個mH成員變數是什麼時候建立的呢?我們前面在分析應用程式的訊息迴圈時,說到當應用程式程式啟動之後,就會載入ActivityThread類的main函式裡面,在這個main函式裡面,在通過Looper類進入訊息迴圈之前,會在當前程式中建立一個ActivityThread例項:
- public final class ActivityThread {
- ......
- public static final void main(String[] args) {
- ......
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- ......
- }
- }
- public final class ActivityThread {
- ......
- final H mH = new H();
- ......
- }
- public class Handler {
- ......
- public Handler() {
- ......
- mLooper = Looper.myLooper();
- ......
- mQueue = mLooper.mQueue;
- ......
- }
- final MessageQueue mQueue;
- final Looper mLooper;
- ......
- }
- public class Looper {
- ......
- public static final Looper myLooper() {
- return (Looper)sThreadLocal.get();
- }
- ......
- }
有了這個Handler物件mH後,就可以通過它來往應用程式的訊息佇列中加入新的訊息了。回到前面的queueOrSendMessage函式中,當它準備好了一個Message物件msg後,就開始呼叫mH.sendMessage函式來傳送訊息了,這個函式定義在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;
- }
- ......
- }
在sendMessageAtTime函式,首先得到應用程式的訊息佇列mQueue,這是在Handler物件構造時初始化好的,前面已經分析過了,接著設定這個訊息的目標物件target,即這個訊息最終是由誰來處理的:
- msg.target = this;
函式最後呼叫queue.enqueueMessage來把這個訊息加入到應用程式的訊息佇列中去,這個函式實現在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;
- }
- ......
- }
第一種情況比較簡單,只要把訊息放在訊息佇列頭就可以了:
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked; // new head, might need to wake up
- 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
- static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {
- NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
- return nativeMessageQueue->wake();
- }
- void NativeMessageQueue::wake() {
- mLooper->wake();
- }
- void Looper::wake() {
- ......
- ssize_t nWrite;
- do {
- nWrite = write(mWakeWritePipeFd, "W", 1);
- } while (nWrite == -1 && errno == EINTR);
- .......
- }
這時候既然管道中有內容可讀了,應用程式的主執行緒就會從這裡的Looper類的pollInner函式返回到JNI層的nativePollOnce函式,最後返回到Java層中的MessageQueue.next函式中去,這裡它就會發現訊息佇列中有新的訊息需要處理了,於就會處理這個訊息。
3. 訊息的處理
前面在分析訊息迴圈時,說到應用程式的主執行緒是在Looper類的loop成員函式中進行訊息迴圈過程的,這個函式定義在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();
- }
- }
- }
- ......
- }
我們繼續以前面分析訊息的傳送時所舉的例子來分析訊息的處理過程。前面說到,在Android應用程式啟動過程原始碼分析這篇文章的Step 30中,ActivityManagerService通過呼叫ApplicationThread類的scheduleLaunchActivity函式通知應用程式,它可以載入應用程式的預設Activity了,而ApplicationThread類的scheduleLaunchActivity函式最終把這個請求封裝成一個訊息,然後通過ActivityThread類的成員變數mH來把這個訊息加入到應用程式的訊息佇列中去。現在要對這個訊息進行處理了,於是就會呼叫H類的dispatchMessage函式進行處理。
H類沒有實現自己的dispatchMessage函式,但是它繼承了父類Handler的dispatchMessage函式,這個函式定義在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);
- }
- }
- ......
- }
- 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;
- ......
- }
- ......
- }
- ......
- }
至此,我們就從訊息迴圈、訊息傳送和訊息處理三個部分分析完Android應用程式的訊息處理機制了,為了更深理解,這裡我們對其中的一些要點作一個總結:
A. Android應用程式的訊息處理機制由訊息迴圈、訊息傳送和訊息處理三個部分組成的。
B. Android應用程式的主執行緒在進入訊息迴圈過程前,會在內部建立一個Linux管道(Pipe),這個管道的作用是使得Android應用程式主執行緒在訊息佇列為空時可以進入空閒等待狀態,並且使得當應用程式的訊息佇列有訊息需要處理時喚醒應用程式的主執行緒。
C. Android應用程式的主執行緒進入空閒等待狀態的方式實際上就是在管道的讀端等待管道中有新的內容可讀,具體來說就是是通過Linux系統的Epoll機制中的epoll_wait函式進行的。
D. 當往Android應用程式的訊息佇列中加入新的訊息時,會同時往管道中的寫端寫入內容,通過這種方式就可以喚醒正在等待訊息到來的應用程式主執行緒。
E. 當應用程式主執行緒在進入空閒等待前,會認為當前執行緒處理空閒狀態,於是就會呼叫那些已經註冊了的IdleHandler介面,使得應用程式有機會在空閒的時候處理一些事情。
相關文章
- Android訊息處理機制(Handler、Looper、MessageQueue與Message)AndroidOOP
- Android 訊息機制:Handler、MessageQueue 和 LooperAndroidOOP
- Android Handler MessageQueue Looper 訊息機制原理AndroidOOP
- Android應用程式訊息處理機制Android
- Android 訊息處理機制:Handler|MessageAndroid
- Handler訊息機制及handler原理(Handler,Looper,MessageQueue),自定義HandlerOOP
- Android訊息機制全面解析(Handler,MessageQueue,Looper,Threadlocal)AndroidOOPthread
- Looper中的訊息佇列處理機制OOP佇列
- Windows應用程式的訊息處理機制Windows
- android訊息機制—HandlerAndroid
- Android訊息機制HandlerAndroid
- Handler訊息處理機制原始碼解析 上原始碼
- 原始碼分析:Android訊息處理機制原始碼Android
- 如何生動形象的理解Android Handler訊息處理機制Android
- Android Handler機制之Handler 、MessageQueue 、LooperAndroidOOP
- Android訊息機制Handler用法Android
- Android訊息傳遞之Handler訊息機制Android
- Android Handler 訊息機制詳述Android
- Android的Handler訊息機制 解析Android
- 深入探索Android訊息機制之HandlerAndroid
- Android 之 Looper、MessageQueue、Handler 與訊息迴圈AndroidOOP
- Handler訊息機制完全解析Handler解析
- Android非同步訊息機制-深入理解Handler、Looper和MessageQueue之間的關係Android非同步OOP
- Android-Handler訊息機制實現原理Android
- Android進階;Handler訊息機制詳解Android
- Android Handler訊息機制原始碼解讀Android原始碼
- Android Handler訊息傳遞機制詳解Android
- Handler訊息傳遞機制
- Android執行緒間訊息機制-Handler原始碼分析(FrameWork)Android執行緒原始碼Framework
- Android中的非同步訊息處理機制Android非同步
- 詳解 Handler 訊息處理機制(附自整理超全 Q&A)
- Android非同步訊息處理機制詳解及原始碼分析Android非同步原始碼
- Android之Handler訊息傳遞機制詳解Android
- Android基本功:Handler訊息傳送機制Android
- 深入理解Android非同步訊息處理機制Android非同步
- android 非同步通訊機制Handler的分析與運用Android非同步
- 從事件驅動程式設計模型分析Handler訊息傳遞機制事件程式設計模型
- Android訊息機制原始碼分析Android原始碼