美文网首页
Handler源码解读

Handler源码解读

作者: leoryzhu | 来源:发表于2019-10-15 19:26 被阅读0次

    我们都知道,Handler在消息机制扮演着非常重要的角色,不过handler消息机制是怎么的呢,今天我们通过源码来看看handler是什么实现消息机制的。

    1、消息发送到消息队列

    handler发送消息有两种,sendMessage(Message msg),和post(Runnable r),其中对应的延迟发送有sendMessageDelayed(Message msg, long delayMillis),postDelayed(Runnable r, long delayMillis)
    首先我们看一下sendMessage(Message msg)

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

    其实内部是调用了sendMessageDelayed(Message msg, long delayMillis),延迟时间为0,继续看下sendMessageDelayed方法

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

    调用了sendMessageAtTime方法,SystemClock.uptimeMillis() + delayMillis很好理解,表示是消息处理的时间,继续看下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);
    }
    

    queue 表示当前的消息队列,紧接着调用了enqueueMessage,目的是把消息加入到消息队列中,再看看

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

    实现上是执行MessageQueue类的 enqueueMessage(msg, uptimeMillis)

    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 {
                   //根据消息执行时间先后把消息插入到消息队列中
                    Message prev;
                    for (;;) {
                        prev = p;
                        p = p.next;
                        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;
        }
    

    mMessages是消息队列MessageQueue队头的消息,表达最先被处理的消息。这样Message就会被添加到消息队列中,如果加入队列队头,会通过本地方法nativeWake唤醒线程
    上面第二种发送消息的方法:postDelayed(Runnable r, long delayMillis),直接看源码

     public final boolean postDelayed(Runnable r, long delayMillis){
            return sendMessageDelayed(getPostMessage(r), delayMillis);
     }
    

    内部也是调用了sendMessageDelayed方法,只不过通过getPostMessage(r)方法把runnable转化成message,方法如下:

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

    其实现获取一个mesaage,然后把runnable放到m.callback中

    2、Looper读取MessageQueue

    第1步已经把消息添加到MessageQueue中了,Looper是怎么读取消息呢,其实就在loop()中,看看loop()关键代码

     public static void loop() {
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
                ...
               try {
                    msg.target.dispatchMessage(msg);//msg.target其实就是发送msg的handler
                    dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
    
            }
        }
    

    不断通过queue.next()循环把要处理的消息找出来,通过handler.dispatchMessage(msg)方法处理消息,再看看 MessageQueue next()方法

    Message next() {
          
            
            for (;;) {
                ...
                nativePollOnce(ptr, nextPollTimeoutMillis);//调用本地方法阻塞nextPollTimeoutMillis时间
                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) {
                        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 {
                            // Got a message.
                            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 {
                        // No more messages.
                        nextPollTimeoutMillis = -1;
                    }
                ...
                 }
        }
    

    代码可以看出next()方法会block直到找到获取已经可以处理的消息。

    3、handler处理message

    在第2步的Looper.loop()中把消息从MssageQueue中取出来,通过调用msg的handler的dispatchMessage方法,msg.target.dispatchMessage(msg);进入到方法里面

    /**
         * Handle system messages here.
         */
        public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    msg.callback就是发送消息post(Runnable r)里面对应的runnable回调方法,优先处理post(Runnable r)方法,没 有runnable就调用handleMessage(msg)方法处理。

    相关文章

      网友评论

          本文标题:Handler源码解读

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