Handler 如何实现定时发送消息的 handler sent 和post的区别


Handler 常用的方法

  1. Handler.postDelayed(Runnable r, long delayMillis)
  2. Handler.sendMessageDelayed(getPostMessage(r), delayMillis)
  3. Handler.sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
  4. Handler.enqueueMessage(queue, msg, uptimeMillis)
  5. MessageQueue.enqueueMessage(msg, uptimeMillis)

那么 handler.postDelayed 和 handler sendMessageDelayed是如何实现时间精准发送消息

handler 在发送消息后,消息会放入MessageQueue中,MessageQueue是一个简单的单向链表

在插入的时候会判断当前消息距离要执行时间和链表中所有消息距离要执行时间大小的比较

链表头时间短,链表尾时间长。

然后再Looper 循环取MessageQueue中的消息的时候会判断当前时间是否是消息可以处理的时间

如果不是,则调用nativePollOnce 进行阻塞,阻塞时间到了,再去取消息

for (;;) {
    if (nextPollTimeoutMillis != 0) {
        Binder.flushPendingCommands();
    }
 
    nativePollOnce(ptr, 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 && msg.target == null) {
            // Stalled by a barrier.  Find the next asynchronous message in the queue.
            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 {
                // 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;
        }
        ...
    }
}

 

handler snet 和 post 本质没有区别都是向messageQueue中加入了消息

有区别在于回调方式的不同,post runnable 回调是回到run方法中

sent 最终会调用到handlerMessage 我们复写的这个方法这里

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}
//获得了message实例,将r赋给callback,接下来还是和sendMessage一致的操作,进入sendMessageDelayed
 private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, 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);
}
 /**
 * Handle system messages here.
 */
   public void dispatchMessage(Message msg) {
  //如果是post,callback不为空,直接进入handleCallback
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
   //如果是sendMessage,且创建handler时没有传入callback,则callback为空,直接进入handleMessage,也就是我们自己复写的处理Message的方法
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

//直接run并不会启动新线程,所以这就是post的runnable里面可以直接更新UI的原因
   private static void handleCallback(Message message) {
    message.callback.run();
}

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM