美文网首页
Handler 源代码理解

Handler 源代码理解

作者: 执念蓝枫 | 来源:发表于2020-08-12 15:58 被阅读0次
    1. Handler通过sent或者post方法将目标Message推送至MessageQueue。

    这里涉及到队列优先级问题。Handler推送目标Message时,会先通过循环将目标Message的执行时间与MessageQueue里原有Message的执行时间进行一一对比,并按照执行时间先后顺序将目标Message插入MessageQueue。

    boolean enqueueMessage(Message msg, long when) {
            if (msg.target == null) {
                throw new IllegalArgumentException("Message must have a target.");
            }
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
    
            synchronized (this) {
                //如果当前消息循环已经结束,直接退出
                if (mQuitting) {
                    IllegalStateException e = new IllegalStateException(
                            msg.target + " sending message to a Handler on a dead thread");
                    Log.w(TAG, e.getMessage(), e);
                    msg.recycle();
                    return false;
                }
    
                msg.markInUse();
                msg.when = when;
                Message p = mMessages;//头部消息
                boolean needWake;
                //如果队列中没有消息,或者当前进入的消息比消息队列中的消息等待时间短,那么就放在消息队列的头部
                if (p == null || when == 0 || when < p.when) {
                    // New head, wake up the event queue if blocked.
                    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;
                }
    
                //调用nativeWake,以触发nativePollOnce函数结束等待
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
    
    2.Looper通过loop()方法获取MessageQueue里的Message。

    loop()方法会通过死循环不断调用MessageQueue的next方法来获取Message,并判断等待时间,如果还需要等待则等到相应时间后提取Message。

    Message next() {
            
            //如果退出消息消息循环,那么就直接退出
            final long ptr = mPtr;
            if (ptr == 0) {
                return null;
            }
    
            int pendingIdleHandlerCount = -1; // -1 only during first iteration
            int nextPollTimeoutMillis = 0;
            for (;;) {
                if (nextPollTimeoutMillis != 0) {
                    Binder.flushPendingCommands();
                }
                
                //执行native层消息机制层,
                //timeOutMillis参数为超时等待时间。如果为-1,则表示无限等待,直到有事件发生为止。
                //如果值为0,则无需等待立即返回。该方法可能会阻塞
                nativePollOnce(ptr, nextPollTimeoutMillis);
    
                synchronized (this) {
                    //获取系统开机到现在的时间,如果使用System.currentMillis()会有误差,
                    final long now = SystemClock.uptimeMillis();
                    Message prevMsg = null;
                    Message msg = mMessages;//头部消息
                    
                    //判断是否是栅栏,同时获取消息队列最近的异步消息
                    if (msg != null && msg.target == null) {
                        do {
                            prevMsg = msg;
                            msg = msg.next;
                        } while (msg != null && !msg.isAsynchronous());
                    }
                    //获取消息,判断等待时间,如果还需要等待则等待相应时间后唤醒
                    if (msg != null) {
                        if (now < msg.when) {//判断当前消息时间,是不是比当前时间大,计算时间差
                            // 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 {
                            // 不需要等待时间或者等待时间已经到了,那么直接返回该消息
                            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 {
                        //没有更多的消息了
                        nextPollTimeoutMillis = -1;
                    }
    
                    // Process the quit message now that all pending messages have been handled.
                    //判断是否已经退出了
                    if (mQuitting) {
                        dispose();
                        return null;
                    }
    
                    // 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.
                    //获取空闲时处理任务的handler 用于发现线程何时阻塞等待更多消息的回调接口。
                    if (pendingIdleHandlerCount < 0
                            && (mMessages == null || now < mMessages.when)) {
                        pendingIdleHandlerCount = mIdleHandlers.size();
                    }
                    //如果空闲时处理任务的handler个数为0,继续让线程阻塞
                    if (pendingIdleHandlerCount <= 0) {
                        // No idle handlers to run.  Loop and wait some more.
                        mBlocked = true;
                        continue;
                    }
                    //判断当前空闲时处理任务的handler是否是为空
                    if (mPendingIdleHandlers == null) {
                        mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                    }
                    mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
                }
    
                //只有第一次迭代的时候,才会执行下面代码
                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);
                        }
                    }
                }
    
                // 重置空闲的handler个数,因为不需要重复执行
                pendingIdleHandlerCount = 0;
                
                //当执行完空闲的handler的时候,新的native消息可能会进入,所以唤醒Native消息机制层
                nextPollTimeoutMillis = 0;
            }
        }
    
    Looper取出Message后会执行message.target.dispatchMessage()方法,即handler的dispatchMessage()方法,并在该方法里执行handleMessage。至此,Handler的一个消息循环结束。

    参考文档:
    https://www.jianshu.com/p/219701879fe4
    https://www.jianshu.com/p/3d8f7ec1017a

    相关文章

      网友评论

          本文标题:Handler 源代码理解

          本文链接:https://www.haomeiwen.com/subject/exdcdktx.html