【问题标题】:android- handler.postDelayed how does it achieve the Delayandroid-handler.postDelayed 是如何实现Delay的
【发布时间】:2020-06-18 02:51:11
【问题描述】:

对于我一直在使用的任何必须延迟的任务:Handler.postDelayed(Runnable r,Long Delay),但我最近才看到文档,上面写着:

使 Runnable r 添加到消息队列中,在经过指定的时间后运行。可运行对象将在附加此处理程序的线程上运行。时基是 SystemClock.uptimeMillis()。在深度睡眠中花费的时间会增加执行的额外延迟。

我对此有两个困惑:

  1. 延迟是通过将Runnable 添加到MessageQueue 来实现的 在指定的延迟时间之后?

    或者,

  2. Runnable 是否立即添加,函数延迟 一个指定的时间。如果是这样,则必须有机制使 Runnable 被出列并放在其他地方,以便其他项目进入 可以处理队列。 Runnable 是如何延迟的,又是如何延迟的 在此延迟期间维护的MessageQueue

【问题讨论】:

  • 只是一个猜测:2. 当可运行对象到达队列的前面时,它的执行时间会被评估,如果它在将来它被发布回队列的后面

标签: java android multithreading


【解决方案1】:

我们称为Handler 的结构以Looper 运行,其中包含MessageQueue。对Handler.post(runnable) 的调用会为MessageQueue 创建一条新消息,并将其放在队列的最后,其时间设置为SystemClock.uptimeMillis()Looper 总是循环检查消息,如果有消息并且已经过了目标时间,就会执行里面的Runnable

澄清一下:

Handler.post(runnable) 发送带有SystemClock.uptimeMillis() 的消息,在下一次检查时,新的SystemClock.uptimeMillis() 变得大于消息的执行时间,从而允许Looper 获取可运行对象并执行它。

现在,如果您使用Handler.postDelayed(runnable, delay),它会使用SystemClock.uptimeMillis() + delay 发布消息,其中延迟以毫秒为单位,我们现在将其称为messageTime。弯针是做什么的?它检查消息,如果SystemClock.uptimeMillis() 小于messageTime,则跳过执行。 Looper 总是循环的,所以有时SystemClock.uptimeMillis() 实际上变得比messageTime 大,此时runnable 有资格执行。

除非您拨打Handler.postAtFrontOfQueue(runnable),否则呼叫总是放在队列的底部,而不是顶部。

完成:

Handler.post(runnable) --> messageTime = SystemClock.uptimeMillis()

Handler.postDelayed(runnable, delay) --> messageTime = SystemClock.uptimeMillis() + delay.

Looper 执行 SystemClock.uptimeMillis() >= messageTime 所在的可运行对象。这就是它的要点。

【讨论】:

  • 带有SystemClock.uptimeMillis() + delay的消息是否放在队列末尾?
【解决方案2】:

runnable 立即添加到消息队列中,这可以在handler classpostDelayed->sendMessageDelayed->sendMessageAtTime 的源代码中看到

public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
    boolean sent = false;
    MessageQueue queue = mQueue;
    if (queue != null) {
        msg.target = this;
        sent = queue.enqueueMessage(msg, uptimeMillis);
    }
    else {
        RuntimeException e = new RuntimeException(
            this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
    }
    return sent;
}

queue.enqueueMessage 运行 for (;;) 以延迟回调。 在这个连续循环中,检查消息的执行时间。您可以在源代码code 中看到这一点

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2011-11-16
  • 2020-06-15
  • 1970-01-01
  • 1970-01-01
  • 2020-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多