美文网首页
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 源代码理解

    1. Handler通过sent或者post方法将目标Message推送至MessageQueue。 这里涉及到队...

  • Handler机制理解

    自己的理解:Handler的基础使用是 Handler handler=new Handler{ handlerM...

  • 深入理解Handler机制之引路篇

    要想深入理解Handler机制,就要理解: Android为何要引入Handler机制? Handler机制究竟是...

  • Android组件_Handler Looper Message

    Android组件_Handler Looper Message理解 一、Handler机制概述 Handler机...

  • Android技术点

    1.handler源码,handler Handler, Looper的理解 2.rxjava机制 rxjava ...

  • handler详解

    Handler理解: 一、基础解读 Android 的Handler 用于处理消息队列 handler 牛津词典的...

  • handler 理解

    简述当接触一个新事物的时候我们要去了解它,认知过程一般是三个为题:这个事物是什么?它为什么要这么做?它是怎样做到的...

  • Handler原理解析

    Handler原理解析 Handler的基本创建步骤 要创建Handler首先需要looper对象,looper的...

  • 线程 Handler 用法及解析

    Handler的理解、用法以及运行机制原理 一、Handler是什么? Handler在我们android开发中是...

  • Handler的不完全解析

    Handler是什么 个人理解:Handler是进程间进行通信的一种方式。 官方:A Handler allows...

网友评论

      本文标题:Handler 源代码理解

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