Android消息机制-Looper MessageQueue Handler

Android有两种特别重要的通信机制,一是Binder IPC,二是消息机制,前者用于进程间通信,后者用于进程内线程间通信。本篇将介绍Android中的消息机制。在介绍Android消息机制之前,先提几个问题,如果您能很好的答出这几个问题,建议您关闭本文章,因为您已经很好的掌握了消息机制的原理了。问题一”Handler,Looper和MessageQueue三者之间对应的关系?“问题二”Looper.loop()是死循环,为什么不卡死主线程“,问题三”您会使用同步屏障,异步消息么?“,问题四”IdleHandler会用不?“。带着问题,开始我们的分析。

消息机制

Android消息机制由三部分组成:消息发送者(Handler),消息队列(MessageQueue),消息循环泵(Looper)。Android使用Looper.prepare()方法创建Looper,并规定每个线程至多对应一个Looper,当在线程中重复创建时会抛出异

    public static void prepare() {
        prepare(true);
    }
 
    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对应一个MessageQueue

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

默认创建Handler时,会使用所在线程的Looper和对应的消息队列

    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 " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

当然我们也可以指定Handler所对应的Looper

    public Handler(Looper looper) {
        this(looper, null, false);
    }

一般最简单的使用方法如下:

public class MainActivity extends Activity {
 
    private static final String TAG = MainActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Handler handler = new Handler();//此处使用应用的线程的Looper
        Message message = handler.obtainMessage();//获取一个Message
        handler.sendMessage(message);//向应用主线程的Looper发送一个消息
        handler.post(new Runnable() {//使用Runnable形式向应用主线程的Looper发送一个消息
            @Override
            public void run() {
                Log.d(TAG, "Runnable message");
            }
        });
    }
}

问题一解答:Thread唯一对应一个Looper,Loope对应唯一的Messagequeue,而一个Looper可以有多个Handler向其发送消息,但是Handler只能对应一个Looper。

MessageQueue

前面我们介绍了一个Looper会对应一个MessageQueue,当创建Looper的同时也会为其创建MessageQueue,MesageQueue构造方法如下:

    private long mPtr; // 保存Native层的MessageQueue
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();//nativeInit是一个native方法,
    }

通过JNI创建Native层的MessageQueue

static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();//创建Native层的消息队列
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }
 
    nativeMessageQueue->incStrong(env);
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

创建Native层的Looper

NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);
    }
}
Looper::Looper(bool allowNonCallbacks) :
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);//创建唤醒的FD
    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
                        strerror(errno));
 
    AutoMutex _l(mLock);
    rebuildEpollLocked();
}
void Looper::rebuildEpollLocked() {
    if (mEpollFd >= 0) {//关闭之前创建的epoll实例
        close(mEpollFd);
    }
 
    // Allocate the new epoll instance and register the wake pipe.
    //创建新的epoll实例
    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 = mWakeEventFd;
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
 
    for (size_t i = 0; i < mRequests.size(); i++) {
        const Request& request = mRequests.valueAt(i);
        struct epoll_event eventItem;
        request.initEventItem(&eventItem);
 
        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
        if (epollResult < 0) {
            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
                  request.fd, strerror(errno));
        }
    }
}

由此可见Android的消息机制不光应用于在Java,在Native层也有应用。创建Java层的MessageQueue的同时也会创建Natvie层的MessageQueue。Natvie层的MessageQueue创建的时候还会创建Native层的Looper,并且通过eventfd创建一个等待/通知机制并返回一个描述mWakeEventFd的int类型的值,同时通过epoll来监控该mWakeEventFd上的状态变化。epoll监控的除了mWakeEventFd,还有一些通过MessageQueue.addOnFileDescriptorEventListener添加的fd,同样通过epoll_ctl函数将fd注册到epoll中进行监听事件,最后通过epoll_wait等待相应的fd上发生事件。那么epoll_wait什么时候唤醒呢?在Java层我们通过JNI调用native方法nativeWake唤醒对应的mWakeEventFd事件,其他的fd需要看自己各自的实现方式,下列三个方法会有对应唤醒操作。 

enqueueMessage(Message, long)
quit(boolean)
removeSyncBarrier(int)

我们从nativeWake调用的地方可以总结出nativeWake的调用时机:queue中没有消息的时候,新加入一条消息时需要wake,移除同步屏障的时候需要wake执行同步消息,至于queue退出时唤醒,个人认为更多的是回收Native层的一些资源比如FD等等。更多关于epoll的使用请查看“什么是IO复用?什么是epoll?”一节。来看下消息如何添加:

    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;
            //mMessages用来记录当前加入的消息的头部消息
            //情况一:队列中没有消息,mMessages==null,此时加入的msg便是消息头部,并将mMessages=msg
            //情况二:队列中有消息,mMessages!=null,此时mMessages为上一次添加的消息
            Message p = mMessages;
            boolean needWake;
            //p == null,说明队列中没有消息,新加入的msg为消息头部
            //when == 0,说明新加入的消息,需要立即执行,将其设置为头部
            //when < p.when,when时间越小,代表越是要提前执行
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {//此时when >= p.when
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    //p == null,说明已查询到队尾
                    //when < p.when,结合when >= p.when,说明新加入的msg刚好找到合适的位置
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //插入到队列中
                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;
    }

Looper

前面说了如何创建MessageQueue以及添加消息,现在来看看Looper是如何消费处理消息的。我们知道Android应用程序的主入口是ActivityThread的main方法,当应用进程成功创建的时候,会进入该方法,并调用Looper.loop()方法进行循环,执行处理队列中的消息。具体相关函数调用如下:

    public static void main(String[] args) {
        Process.setArgV0("<pre-initialized>");
        Looper.prepareMainLooper();//创建Looper
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        Looper.loop();//进入循环遍历消息队列
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

Looper.loop方法很简单,通过for循环从MessageQueue中获取消息,并且发送给对应的Handler进行处理。

    public static void loop() {//loop循环遍历MessageQueue
        final Looper me = myLooper();//获取当前线程的Looper
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//获取对应Looper的MeeageQueue
 
        // 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();
 
        boolean slowDeliveryDetected = false;
 
        for (;;) {
            //取MessageQueue中的下一个Message
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            try {
                msg.target.dispatchMessage(msg);
                }
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            msg.recycleUnchecked();
        }
    }

该方法看似简单,其实暗藏一个知识点,引出我们的问题”loop中是无限循环,为什么android的主线程却没有出现卡死现象?“带着问题继续查看MessageQueue的next代码,至于MessageQueue如何创建添加请查看MessageQueue创建一节。继续分析MessageQueue的next方法

    Message next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
 
            nativePollOnce(ptr, nextPollTimeoutMillis);//JNI执行native方法
 
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;//取得队列头部消息
                if (msg != null && msg.target == null) {//当msg.target == null说明该消息是一个同步屏障,该消息之后的所有同步消息不执行
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {//遍历异步消息
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                //情况一:没有同步屏障,此时msg=队头消息
                //情况二:存在同步屏障,msg=when最小的异步消息
                //情况三:msg == null
                if (msg != null) {
                    if (now < msg.when) {//还没有到达执行时间,休眠nextPollTimeoutMillis
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;//取出msg,并设置prevMsg.next = msg.next,此时队头仍然是mMessages
                        } else {
                            mMessages = msg.next;//取出队头,并重新设置队头消息
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
 
                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }
 
                //处理IdleHandler部分,一种很有意思的接口
                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                //每次循环开始pendingIdleHandlerCount都会被设置为-1
                //mMessages == null,没消息的时候,此时MessageQueue会wait,在wait之前处理IdleHandler逻辑
                //now < mMessages.when,仍然需要wait nextPollTimeoutMillis这么长时间,在wait之前处理IdleHandler逻辑
                //总结就是当MessageQueue进入空闲的之前或者当前时间之前的消息都处理完等待后续消息执行之前,进行处理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逻辑
            // 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(TAG, "IdleHandler threw exception", t);
                }
 
                if (!keep) {//idler.queueIdle()返回false时,说明该IdleHandler只执行一次
                    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;
        }
    }

在调用MessageQueue的next方法取消息的时候,如果不存在同步屏障,直接去队头消息,如果队头消息的执行时间已经达到,我们被立即返回并执行,如果还未到达,需要等待相应的时间。如果取消息的时候,我们通过postSyncBarrier设置了同步屏障,同步屏障消息的target==null,排在同步屏障之后的同步消息都不能执行,只取后续的异步消息(即Message.isAsynchronous==true),当然我们也可以通过removeSyncBarrier移除该同步屏障。那么这个同步屏障的有什么应用的地方么?Android系统界面绘制的时候会用到同步屏障,作用在于保证界面绘制的消息高优先级执行。关于AndroidView的绘制流程后续也会进行分析。之前,我们一直在强调没有消息或者消息执行时间为到达的时候MessageQueue会进行wait,要知道我们执行的是死循环,wait是如何实现的呢?我们来看下native方法nativePollOnce(ptr, nextPollTimeoutMillis)的执行,分析nativePollOnce之前建议结合”MessageQueue创建“这一节。

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

调用Native层MessageQueue的pollOnce

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    mLooper->pollOnce(timeoutMillis);
    mPollObj = NULL;
    mPollEnv = NULL;
 
    if (mExceptionObj) {
        env->Throw(mExceptionObj);
        env->DeleteLocalRef(mExceptionObj);
        mExceptionObj = NULL;
    }
}

继续调用Native层Looper的pollOnce方法,此时timeoutMillis有三种情形:-1(无限等待),0(非阻塞,立即返回),>0(阻塞等待timeoutMillis时间后返回)。

inline int pollOnce(int timeoutMillis) {
    return pollOnce(timeoutMillis, NULL, NULL, NULL);
}
 
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for (;;) {
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE
                ALOGD("%p ~ pollOnce - returning signalled identifier %d: "
                        "fd=%d, events=0x%x, data=%p",
                        this, ident, fd, events, data);
#endif
                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }
 
        if (result != 0) {
#if DEBUG_POLL_AND_WAKE
            ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
            if (outFd != NULL) *outFd = 0;
            if (outEvents != NULL) *outEvents = 0;
            if (outData != NULL) *outData = NULL;
            return result;
        }
 
        result = pollInner(timeoutMillis);
    }
}
 
int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
#endif
 
    // 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;
        }
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
                this, mNextMessageUptime - now, timeoutMillis);
#endif
    }
 
    // Poll.
    int result = POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;
 
    // We are about to idle.
    mPolling = true;
 
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
 
    // No longer idling.
    mPolling = false;
 
    // Acquire lock.
    mLock.lock();
 
    // 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) {
#if DEBUG_POLL_AND_WAKE
        ALOGD("%p ~ pollOnce - timeout", this);
#endif
        result = POLL_TIMEOUT;
        goto Done;
    }
 
    // Handle all events.
#if DEBUG_POLL_AND_WAKE
    ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
#endif
 
    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 {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;
                if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
                if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
                if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
                if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {
                ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
                        "no longer registered.", epollEvents, fd);
            }
        }
    }
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();
 
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
                ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
                        this, handler.get(), message.what);
#endif
                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;
        }
    }
 
    // Release lock.
    mLock.unlock();
 
    // 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;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
            ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
                    this, response.request.callback.get(), fd, events, data);
#endif
            // 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;
}

nativePollOnce相关的代码很长,但是没有逻辑上相当简单,主要精华就是一个epoll_wait方法,我们还需要更多的留意timeoutMillis参数的值,当timeoutMillis=-1,nativePollOnce方法进入无限等待,这就是Looper.loop()方法死循环而不卡死主线程浪费CPU资源的原因,=0时nativePollOnce立即返回,>0时nativePollOnce方法阻塞等待timeoutMillis时间后再返回,此时这个timeoutMillis就是等待消息执行时间到达的时间,也就是我们通过nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE)计算得到值。至此我们回头再看MessageQueue的next方法,是否能够找到一些您心中的困惑呢?

IdleHandler

分析MessageQueue.next的方法的时候,我们说了不管MessageQueue中是否存在消息,只要MessageQueue wait之前都会先处理IdleHandler相关的逻辑,那么这个作用是什么呢?我们来看下系统中的一处用法,来体会其中的妙处:

    @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
        //省略resume Activity和调用界面绘制相关的代码
        Looper.myQueue().addIdleHandler(new Idler());
    }
 
    private class Idler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            ActivityClientRecord a = mNewActivities;
            boolean stopProfiling = false;
            if (mBoundApplication != null && mProfiler.profileFd != null
                    && mProfiler.autoStopProfiler) {
                stopProfiling = true;
            }
            if (a != null) {
                mNewActivities = null;
                IActivityManager am = ActivityManager.getService();
                ActivityClientRecord prev;
                do {
                    if (localLOGV) Slog.v(
                        TAG, "Reporting idle of " + a +
                        " finished=" +
                        (a.activity != null && a.activity.mFinished));
                    if (a.activity != null && !a.activity.mFinished) {
                        try {
                            am.activityIdle(a.token, a.createdConfig, stopProfiling);
                            a.createdConfig = null;
                        } catch (RemoteException ex) {
                            throw ex.rethrowFromSystemServer();
                        }
                    }
                    prev = a;
                    a = a.nextIdle;
                    prev.nextIdle = null;
                } while (a != null);
            }
            if (stopProfiling) {
                mProfiler.stopProfiling();
            }
            ensureJitEnabled();
            return false;
        }
    }

从代码中可以看出,Android在handleResumeActivity最后一行添加了一个Idle的IdleHandler到系统主线程的Looper中去,他的意思就是当系统中处理完应用的界面绘制的消息之后,在进入wait之前执行一下Idle的queueIdle逻辑。比如说我们想在应用绘制好界面之后弹出一个提示或者做点其他操作,我们同样实现自己的IdleHandler,并将其添加到应用主线程的Looper中去就行了。

什么是IO复用?什么是epoll?--仅仅是抛砖引玉

IO复用内核提供的一种同时监控多个文件描述符状态改变的一种能力。例如当进程需要操作多个IO相关描述符时(例如服务器程序要同时查看监听socket和大量业务socket是否有数据到来),需要内核能够监控这许多描述符,一旦这些描述符有就绪(或者状态改变了)就告诉主动告诉进程哪些描述符已经就绪,这样站在进程的角度,就不需要挨个的查看每个描述符是否就绪。IO模型有五种:阻塞IO模型,非阻塞IO模型,IO复用模型,信号驱动IO模型,异步IO模型 --------------------- 本描述来自 逍遥子_ 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/houjixin/article/details/27662489

而epoll就是使用的IO多路复用模型。我们一般使用epoll是会通过epoll_create创建一个epoll实例对象,返回的是一个文件描述符。epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)用来增加或移除被epoll所监听的文件描述符,其中epfd是epoll_create创建返回的文件描述符,op指的是要进行的操作类型可能为EPOLL_CTL_ADD(注册新的fd到epfd中)EPOLL_CTL_MOD(修改已经注册的fd的监听事件)EPOLL_CTL_DEL(从epfd中删除一个fd),fd指的是是需要监听的fd,最后一个参数告诉内核需要监听什么事。epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)等待事件的产生。

更多epoll使用请关注https://blog.csdn.net/hpghy123456/article/details/8951154
                                 
https://www.cnblogs.com/ypwen/p/4725532.html
更多select/poll/epoll请关注http://www.cnblogs.com/Anker/p/3265058.html
更多IO复用\阻塞IO\非阻塞IO\同步IO\异步IO请关注https://blog.csdn.net/houjixin/article/details/27662489

写在最后--此时无声胜有声

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值