滴滴面试的时候问到了这个问题,在巴掌神的demo帮助下,估计想考的就是这个吧,ps面试官不说答案逼都让他装了0.-,建议当面试官的朋友们最好准备一下答案比较好,在面试的时候给予被面试者帮助,面试不仅是一次求职体验,也是一次技术交流嘛,好了言归正传。
这里先放出巴掌大神的github地址予以鸣谢:https://github.com/JeasonWong
当代码执行到postDelayed里面的run的时候 log 是 3150 毫秒;
该方法按照代码上示意应该是 上一个runnable执行之后再延时1毫秒执行,应该是4000+毫秒才对(之力说的计时是否准确应该是相对准确,因为执行代码需要花时间的),但是输出结果是3150毫秒,那就说明你设定的延时任务其实是不准确的,上图红色字标注说明了原因,下面将结合源码得出结论。
以下android framwork 源码均为api 25
我们看一下Handler类postDelayed方法调用了sendMessageDelayed方法的源码
这里可以发现调用postDelayed的时候要执行延时方法的时间就已经被算好了
我们再来看到MessageQueue类的next方法
如果走到 now<msg.when 会走到后面的continue (375行)然后等到时间到了 再拿一次msg
如果 走到 else 就直接返回,如下图
返回msg 之后 就走到 handler.dispatchMessage去执行回调了
说明一下,msg.target就是handler对象(不懂的可以读一下Handler 638行enqueueMessage方法源码)
由于Loop.loop里面消息是串行取出并发给handler.dispatchMessage的,而postDelayed函数调用的时候执行时间就已经算好了,这里假设调用postDelayed的当前时间SystemClock.uptimeMillis
为1s,那么算上delayMillis就是1s+1s=2s,也就是系统开机后第2s,它应该在系统时间的第2s就应该被执行了,但因为消息执行是串行执行的,上一个runnable 里面调用了Thread.sleep(3000)
,也就是说上一个任务执行需要3s,系统时间一下就到了第3S,那么轮到处理第二个延时runnable的时候,MessageQueue类的next方法再执行到`
138行if(now < msg.when)
的时候,now是系统开机后第3秒,而此时msg.whe 是开机后第2秒,那么就会走到下面的else分支,就立刻return了该msg,然后由handler.dispatchMessage处理,执行到该runnable的run方法,此时Log打印的时间就是3150毫秒了.
handler.postDelayed函数延时执行计时是否准确,答:当上一个消息存在耗时任务的时候,会占用延时任务执行的时机,此时是不准确的。那么如何准确执行延时任务呢,可以开启一个HandlerThread为一个专门的唯一的延时消息服务。(或许你会说成本很大,但是我没想到啥好办法,有好办法可以留言。)
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章