【學習記錄】Android深入學習之消息處理機制

學習過程

跟著鴻洋_的博客的思路,結合7.0的源碼進行學習,同時參考其他好的文章。

概述

主要涉及四個類:Looper、Handler、Message、MessageQueue。
Message是消息對象,MessageQueue是消息隊列。Looper負責創建消息隊列,并進入無限循環不斷從消息隊列中讀取消息。而Handler負責發送消息到消息隊列,以及消息的回調處理。

Looper

1. Looper類的作用

源碼的類注釋中已經把Looper類的作用和使用方法說得很清楚了。

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  *
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.
  *
  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {@link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
  */

Looper類的作用就是讓線程進行消息循環。如果一個線程需要消息循環,只需要調用Looper類的prepare方法和loop方法就可以了。因此,Looper類中我們主要關注prepare和loop這兩個方法,它們都是static方法。

2. prepare()方法

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));

}

這里創建了一個Looper對象,然后保存到一個ThreadLocal的靜態變量中。當sThreadLocal中取出的對象不為null時,會拋出異常,保證一個線程中只有一個Looper對象。ThreadLocal后面再研究。

然后看Looper的構造方法。

private Looper(boolean quitAllowed)  {
    
    mQueue = new MessageQueue(quitAllowed);
    
    mThread = Thread.currentThread();

}

創建了一個MessageQueue(消息隊列)。

3. loop()方法

/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
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 (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        final long traceTag = me.mTraceTag;
        if (traceTag != 0) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }
        try {
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }

        msg.recycleUnchecked();
    }
}

其中,Binder.clearCallingIdentity()的作用不清楚,先忽略。
執行流程:

  1. myLooper方法獲取sThreadLocal中保存的Looper實例。因此再loop方法執行前應該先執行prepare方法。
  2. 進入無限循環。
    1. 從消息隊列中取出一條消息,如果沒有消息則會阻塞;如果消息隊列已釋放,則會返回null,退出消息循環。
    2. 調用msg.target的dispatchMessage方法處理消息。target就是Handler的實例,負責接收處理這個消息。
    3. 回收msg資源。

4. Looper類小結

  1. 每個線程最多只能有一個Looper對象。每個Looper對象創建并持有一個MessageQueue對象。
  2. 通過調用Looper.loop方法使當前線程進入消息循環。當前線程的Looper對象循環從消息隊列中取出消息,交由相應的Handler對象去處理。

Handler

1. Handler類的作用

還是看源碼中的類注釋。

/**
 * A Handler allows you to send and process {@link Message} and Runnable
 * objects associated with a thread's {@link MessageQueue}.  Each Handler
 * instance is associated with a single thread and that thread's message
 * queue.  When you create a new Handler, it is bound to the thread /
 * message queue of the thread that is creating it -- from that point on,
 * it will deliver messages and runnables to that message queue and execute
 * them as they come out of the message queue.
 * 
 * <p>There are two main uses for a Handler: (1) to schedule messages and
 * runnables to be executed as some point in the future; and (2) to enqueue
 * an action to be performed on a different thread than your own.
 * 
 * <p>Scheduling messages is accomplished with the
 * {@link #post}, {@link #postAtTime(Runnable, long)},
 * {@link #postDelayed}, {@link #sendEmptyMessage},
 * {@link #sendMessage}, {@link #sendMessageAtTime}, and
 * {@link #sendMessageDelayed} methods.  The <em>post</em> versions allow
 * you to enqueue Runnable objects to be called by the message queue when
 * they are received; the <em>sendMessage</em> versions allow you to enqueue
 * a {@link Message} object containing a bundle of data that will be
 * processed by the Handler's {@link #handleMessage} method (requiring that
 * you implement a subclass of Handler).
 * 
 * <p>When posting or sending to a Handler, you can either
 * allow the item to be processed as soon as the message queue is ready
 * to do so, or specify a delay before it gets processed or absolute time for
 * it to be processed.  The latter two allow you to implement timeouts,
 * ticks, and other timing-based behavior.
 * 
 * <p>When a
 * process is created for your application, its main thread is dedicated to
 * running a message queue that takes care of managing the top-level
 * application objects (activities, broadcast receivers, etc) and any windows
 * they create.  You can create your own threads, and communicate back with
 * the main application thread through a Handler.  This is done by calling
 * the same <em>post</em> or <em>sendMessage</em> methods as before, but from
 * your new thread.  The given Runnable or Message will then be scheduled
 * in the Handler's message queue and processed when appropriate.
 */

Handler用于發送和處理Message和Runnable對象。Handler對象在創建時關聯當前線程的MessageQueue,且每個Handler對象只能關聯一個MessageQueue。Handler對象發送Message和Runnable對象到關聯的MessageQueue,然后當它們從MessageQueue中移出時,負責執行它們。

Handler的主要用途有兩個:

  1. 定時執行message或runnable。
  2. 讓其他線程執行某個操作。比如,在非UI線程發送一個消息,讓UI線程更新界面。

Handler中重要的有以下幾組方法:

  1. 構造方法
  2. sendMessage方法
  3. post方法
  4. dispatchMessage方法

2. 構造方法

Handler中有很多構造方法,但是最終分別進入到兩個構造方法中。先來看下這兩個構造方法有什么不同。

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        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());
        }
    }

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

第二個構造方法前面那段主要是當Handler的之類不是static類時,警告可能會導致內存泄漏。忽略這個,兩個方法的區別就在于mLooper這個成員變量的來源。第一個方法由參數傳入,而第二個方法是獲取當前線程的Looper。可以看到,構造方法里面就是對幾個成員變量賦值而已。這里先了解一下這幾個成員變量的作用。

  • mLooper:Looper,消息循環
  • mQueue:MessageQueue,消息隊列,就是mLooper中持有的那個
  • mCallback:Handler.CallBack,Handler中聲明的接口,用于處理消息
  • mAsynchronous:boolean,發送的消息是否是異步的。那么,這個異步到底是什么意思呢?我們在后面MessageQueue的next方法中再去詳細了解。

3. sendMessage方法

sendMessage有一系列的方法:

  • sendMessage(Message msg): boolean
  • sendEmptyMessage(int what): boolean
  • sendEmptyMessageDelayed(int what, long delayMillis): boolean
  • sendMessageDelayed(Message msg, long delayMillis): boolean
  • sendEmptyMessageAtTime(int what, long uptimeMillis): boolean
  • sendMessageAtTime(Message msg, long uptimeMillis): boolean
  • sendMessageAtFrontOfQueue(Message msg): boolean

其中,sendMessage、sendEmptyMessage、sendMessageDelayed、sendEmptyMessageDelayed和sendEmptyMessageAtTime方法都調用sendMessageAtTime方法。所以,我們重點看sendMessageAtTime方法和sendMessageAtFrontOfQueue方法。

sendMessageAtTime方法

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);
}

enquueMessage方法只是調用MessageQueue的enqueueMessage方法。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

uptimeMillis是消息分發的時間,基于SystemClock.uptimeMillis()。比如,sendMessageDelayed方法中使用SystemClock.uptimeMillis()加上延遲的時間。在消息隊列中,消息是按分發時間的先后排列的。因此,這里的msg會插入到所有分發時間在uptimeMillis之前的消息后面。

sendMessageAtFrontOfQueue方法

public final boolean sendMessageAtFrontOfQueue(Message msg) {
    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, 0);
}

顧名思義,sendMessageAtFrontOfQueue方法就是把消息插入到隊列的最前面。和sendMessageAtTime唯一的不同是,在調用enqueueMessage方法時傳的uptimeMillis參數是0。用0來表示插入到消息隊列最前面,也是比較自然的做法。

4. post方法

post方法把Runable對象添加到消息隊列中,也有一系列方法。

  • post(Runnable r): boolean
  • postAtTime(Runnable r, long uptimeMillis): boolean
  • postAtTime(Runnable r, Object token, long uptimeMillis): boolean
  • postDelayed(Runnable r, long delayMillis): boolean
  • postAtFrontOfQueue(Runnable r): boolean

這些方法實現都類似,都是通過getPostMessage方法,獲取一個Message,同時把Runnable存到Message中,然后調用sendMessage方法。

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

比較特殊的是帶有token參數的postAtTime方法,這里的token是傳給消息接收者的數據,會保存到Message的成員變量obj中。

private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    m.obj = token;
    m.callback = r;
    return m;
}

5. dispatchMessage方法

dispatchMessage方法就是前面Looper中調用的處理消息的方法。

msg.target.dispatchMessage(msg);

先看dispatchMessage方法的源碼。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

如果消息中帶有callback,直接執行callback(就是Message帶的Runnable);如果Handler中設置了CallBack,則調用CallBack來處理消息;前面兩個都沒有的話,才是調用handleMessage方法。handleMessage是空方法,子類可以重寫該方法來處理消息。

6. Handler類小結

  1. Handler創建時會關聯一個Looper和Looper中持有的MessageQueue。
  2. Handler可以在任意線程發送消息到關聯的MessageQueue。
  3. Handler在關聯的Looper所在線程處理自己發送的消息。
  4. Hander主要用于定時任務和在其他線程執行任務。

MessageQueue

看完了Looper和Handler,已經基本理清了消息機制。再來看一下消息隊列是怎么實現的。主要看一下把消息加入隊列和從隊列中取消息的實現。

1. 消息加入隊列

MessageQueue的enqueueMessage方法負責把消息加入隊列中。就是Handler中添加消息到消息隊列調用的方法。下面貼的代碼中省略了一下不影響主要邏輯的部分。

boolean enqueueMessage(Message msg, long when) {
    ......

    synchronized (this) {
        ......

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            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; 
            prev.next = msg;
        }

        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

成員變量mMessages是消息隊列的頭部,是一個Message對象。MessageQueue中通過Message的next形成一個鏈表。如果待插入的消息的分發時間是0,表示直接插入到隊列頭部。如果隊列頭部Message為空,或者待插入消息的分發時間小于隊列頭部Message,也把消息插入到隊列頭部。如果不滿足插入到頭部的條件的話,就遍歷消息隊列,按分發時間找到合適的插入位置。

2. 從隊列中獲取下一條消息

在Looper中已經看到,MessageQueue的next方法負責從隊列中取下一條消息。

Message next() {
    ...

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // 找下一個消息。找到的話就返回這個消息。
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // 被Barrier阻塞。找隊列中的下一個異步消息。
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // 下一個消息的分發時間還沒到。設置一個時間,等到消息準備分發時再喚醒。
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 有一個可以分發的消息。
                    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 {
                // 沒有消息,也可能是消息都被Barrier阻塞了。
                nextPollTimeoutMillis = -1;
            }

            // 消息循環準備退出。釋放資源,并且返回null。
            if (mQuitting) {
                dispose();
                return null;
            }

            // pendingIdleHandlerCount初始值為-1,所以第一次會去獲取IdleHandlers的數量。
            // IdleHandler在需要等待下一條消息時去運行,因為這時是空閑的。
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                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);
        }

        // 執行IdleHandler
        // 只在第一次迭代時會執行,因為后面會把pendingIdleHandlerCount設成0
        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(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // 把pendingIdleHandlerCount設成0,后面的迭代不會再去執行IdleHandlers。
        pendingIdleHandlerCount = 0;

        // 執行完IdleHandler,可能已經有新的消息了,所以不需要再等待了。
        nextPollTimeoutMillis = 0;
    }
}

這個方法還是比較復雜的,所以我畫了個流程圖,能夠看得清楚一些。

MessageQueue的next方法流程圖.png

通過流程圖已經能理清next方法的執行過程。但是,還有兩個需要解釋的地方。一個是Barrier和異步消息,另一個是nativePollOnce這個方法。

Barrier和異步消息

Barrier是什么?
Barrier是阻塞器,會阻塞消息隊列。它也是一個Message對象,只不過它的target是null。從next方法中可以看到,在Barrier后面所有消息,除了異步消息外都無法執行。
MessageQueue中對外提供了post和remove的方法。

public int postSyncBarrier();
public void removeSyncBarrier(int token);

調用post方法時,會創建一個空的Message對象,時間設為當前的系統時間,同時生成一個token,保存在Message中。這個Message對象會像普通的消息一樣被插入到消息隊列中。調用remove方法時,根據token從消息隊列中找到相應的Barrier,然后移除。
看一個具體的例子,這是ViewRootImpl中的一段代碼。

void scheduleTraversals() {
    ...
    mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
    ...
}

void unscheduleTraversals() {
    ...
    mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    ...
}

當要阻塞消息隊列時,通過Handler獲取到MessageQueue,然后直接調用MessageQueue的postSyncBarrier方法,保存下token。需要取消消息隊列的阻塞時,通過先前保存的token去移除Barrier。

nativePollOnce方法

nativePollOnce是一個native方法。它的實現在frameworks/base/code/jni目錄下的android_os_MessageQueue.cpp中。想要了解怎么找到這個實現的,可以閱讀這篇文章:Android JNI原理分析

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}

這里去調用了NativeMessageQueue的pollOnce方法。NativeMessageQueue的對象是在Java層的MessageQueue創建時,同時創建的。

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    ...
    mLooper->pollOnce(timeoutMillis);
    ...
}

這里調用mLooper的pollOnce方法。這里的mLooper是JNI層的Looper,是在創建NativeMessageQueue時創建的。這個類的實現在system/core/libutils/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);
    }
}

我們把pollOnce方法中不太重要的部分都去掉,只留下最主要的部分。實際上就是循環去調用pollInner方法,當pollInner方法的返回結果不為0時,這個方法就可以返回了。下面來看一下pollInner方法的實現。

int Looper::pollInner(int timeoutMillis) {

    // Adjust the timeout based on when the next message is due.
    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
        if (messageTimeoutMillis >= 0
                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
            timeoutMillis = messageTimeoutMillis;
        }
    }

    // Poll.
    int result = POLL_WAKE;
    ...

    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);


    // Rebuild epoll set if needed.
    if (mEpollRebuildRequired) {
        mEpollRebuildRequired = false;
        rebuildEpollLocked();
        goto Done;
    }

    // Check for poll error.
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
        result = POLL_ERROR;
        goto Done;
    }

    // Check for poll timeout.
    if (eventCount == 0) {
        result = 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 == mWakeEventFd) {
            if (epollEvents & EPOLLIN) {
                awoken();
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
            }
        } else {
            ...
        }
    }
Done: ;

    // Invoke pending message callbacks.
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            // Remove the envelope from the list.
            // We keep a strong reference to the handler until the call to handleMessage
            // finishes.  Then we drop it so that the handler can be deleted *before*
            // we reacquire our lock.
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();

                handler->handleMessage(message);
            } // release handler

            mLock.lock();
            mSendingMessage = false;
            result = POLL_CALLBACK;
        } else {
            // The last message left at the head of the queue determines the next wakeup time.
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }

    ...

    // Invoke all response callbacks.
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;

            // Invoke the callback.  Note that the file descriptor may be closed by
            // the callback (and potentially even reused) before the function returns so
            // we need to be a little careful when removing the file descriptor afterwards.
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd, response.request.seq);
            }

            // Clear the callback reference in the response structure promptly because we
            // will not clear the response vector itself until the next poll.
            response.request.callback.clear();
            result = POLL_CALLBACK;
        }
    }
    return result;
}

pollInner方法中調用了epoll_wait(),等待消息到來,或者等到超時返回。如果有消息到來,則進行處理。

poolInner方法的流程:(摘自[M0]Android Native層Looper詳解

  • 調整timeout:

  • mNextMessageUptime 是 消息隊列 mMessageEnvelopes 中最近一個即將要被處理的message的時間點。

  • 所以需要根據mNextMessageUptime 與 調用者傳下來的timeoutMillis 比較計算出一個最小的timeout,這將決定epoll_wait() 可能會阻塞多久才會返回。

  • epoll_wait():
    epoll_wait()這里會阻塞,在三種情況下回返回,返回值eventCount為上來的epoll event數量。

  • 出現錯誤返回, eventCount < 0;

  • timeout返回,eventCount = 0,表明監聽的文件描述符中都沒有事件發生,將直接進行native message的處理;

  • 監聽的文件描述符中有事件發生導致的返回,eventCount > 0; 有eventCount 數量的epoll event 上來。

  • 處理epoll_wait() 返回的epoll events.
    判斷epoll event 是哪個fd上發生的事件

  • 如果是mWakeEventFd,則執行awoken(). awoken() 只是將數據read出來,然后繼續往下處理了。其目的也就是使epoll_wait() 從阻塞中返回。

  • 如果是通過Looper.addFd() 接口加入到epoll監聽隊列的fd,并不是立馬處理,而是先push到mResponses,后面再處理。

  • 處理消息隊列 mMessageEnvelopes 中的Message.

  • 如果還沒有到處理時間,就更新一下mNextMessageUptime

  • 處理剛才放入mResponses中的事件.

  • 只處理 ident 為POLL_CALLBACK的事件。其他事件在 pollOnce 中處理

參考資料

  1. Android 異步消息處理機制 讓你深入理解 Looper、Handler、Message三者關系
  2. android的消息處理機制(圖+源碼分析)——Looper,Handler,Message
  3. Android消息處理機制(Handler、Looper、MessageQueue與Message)(里面關于同步消息、異步消息講得很清楚)
  4. Android應用程序消息處理機制(Looper、Handler)分析
  5. Android JNI原理分析
  6. [M0]Android Native層Looper詳解
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容