Handler源码解析(二)

20 篇文章 0 订阅

首先呢,先说一下Handler发送消息如何到MessageQueue中的呢

下面就是发送方法的源码

先看一下post发送方法

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

他调用了sendMessageDekayed();接下来看看这个方法中使用的是什么呢

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

在这个方法中呢,调用了sendMessageAtTime();

接下来呢我们看看常用的sendMessage()发送方法

  public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }

在sendMessage方法中调用了sendMessageDelayed()瞅瞅这个

  public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

最后呢。还是调用了这个sendMessageAtTime()

所以,重点来了!!!!!!

最后的一个总结就是当我们使用handler的时候创建Handler对象,使用handler发送消息,不管你调用什么方法呢,最终都会走到sendMessageAtTime()方法中去。这里呢我就不举过多的例子了。想看一下自己去瞅瞅吧

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

看这个return返回的呢,看调用sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)

SystemClock.uptimeMillis()表示系统开机到当前的时间总数,单位是毫秒,但是,当系统进入深度睡眠(CPU休眠、屏幕休眠、设备等待外部输入)时间就会停止,但是不会受到时钟缩放、空闲或者其他节能机制的影响。这个我去网上查了一下
delayMillis这个呢是你传入的延迟时间。

所以,重点来了!!!!!!
SystemClock.uptimeMillis()他呢就是系统时间 +delayMillis你传入的延迟时间
这个就是handler接收延迟时间的办法

既然最后都调用这个方法,那我们来看看这个sendMessageAtTime 方法。

    public boolean sendMessageAtTime(@NonNull 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);
    }

最终呢,通过sendMessageAtTime()调用enqueueMessage()

   private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

queue类型是MessageQueue()。
这样就把消息发送到MessageQueue 中 enqueueMessage()中

终于到MessageQueue中了

那么我们看一下MessageQueue

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }

        synchronized (this) {
            if (msg.isInUse()) {
            //判断msg是否正在使用
                throw new IllegalStateException(msg + " This message is already in use.");
            }

            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是否正在使用
            msg.markInUse();
            //给msg复制时间  当前when代表系统时间+延迟时间
            msg.when = when;
            //取出表头
            Message p = mMessages;
            //是否需要唤醒的一个状态
            boolean needWake;
            //msg这里代表的是要发送的消息  。  when是一个延迟时间(系统时间+延迟时间)
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                //这里判断一共有三点
                //1、队列为空时,他会直接放在队列头
                //2.当when为0时呢,会直接放在队列头,但是这个地方再上一期的构造方法中呢,都能看到大部分构造方法是使用系统时间+延迟时间。
                //在最下面我会详细列出来那些为0的
                //3.when<p.when  代表要发送消息的延迟时间如果小于对头消息的延迟时间那么会放在队列头
                msg.next = p;
                //将要发送的消息的指针,指向队列头
                mMessages = msg;
                //将msg赋值给对头
                needWake = mBlocked;
                //新头,如果阻塞则唤醒事件队列。
            } else {
                // 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;
                //创建一个Message
                for (;;) {
                //将队列当前的消息拿出来。赋值给pev
                    prev = p;
                    //取出下一个下一个消息。并且赋值给p
                    p = p.next;
                    if (p == null || when < p.when) {
                    //p == null 代表没有消息了。   when<p.when   当前消息延迟时间<取出的这个消息延迟时间
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //这里的逻辑跟之前一样
                //就是更改当前message的指针,指向p
                //将上一个指针指向msg
                
                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;
    }

接下会列出方法。这方法呢,会让when等于0.会直接放在队列头

sendEmptyMessageAtTime()
sendMessageAtTime() //这个方法是send方法最后通过它发送给enqueueMessage
sendMessageAtFrontOfQueue()
postAtFrontOfQueue()
postAtTime()

因为没有增加系统时间。所以他when会为0
但是我没有区分这几个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值