Handler源码解读

2019-10-15  本文已影响0人  leoryzhu

我们都知道,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)方法处理。

上一篇下一篇

猜你喜欢

热点阅读