2024年字节跳动面试-Handler相关

问题:Handler.postDelayed原理,修改手机系统时间是否对延迟消息有影响。

回答:

修改系统时间对延迟消息无影响,原因是

  • 存入队列时,SystemClock.uptimeMillis() + delayMillis设置的msg.when

  • 取出队列时,最终调用到了nativePollOnce(long ptr, int timeoutMillis),这里用到的也是 msg.when - SystemClock.uptimeMillis()。SystemClock.uptimeMillis()是自启动以来非睡眠正常运行时间的毫秒数, 是一个相对的时间,与修改手机系统时间SystemClock.currentTimeMillis()无关。修改手机系统时间不会改变自启动以来非睡眠正常运行时间的毫秒数,即不会改变SystemClock.uptimeMillis()的值。

所以,与修改系统时间对延迟消息无影响。

private native void nativePollOnce(long ptr, int timeoutMillis);
final long now = SystemClock.uptimeMillis()
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);
} 

加入队列时:Handler.postDelayed()的调用路径

一步一步跟一下Handler.postDelayed()的调用路径:

  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)

取出队列时:MessageQueue.next()

@UnsupportedAppUsage
Message next() {
    
    
    
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; 
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);

需要注意的是ChatGPT的回答不完全正确,但有一定的参考意义。所以贴在了下面。

以下是ChatGPT的回答:

Handler.postDelayed 原理:

  • 当你调用 Handler.postDelayed(Runnable r, long delayMillis) 时,实际上是将一个消息(Message)放入消息队列,并设置一个执行时间,这个执行时间是当前时间加上你指定的延迟时间。
  • 消息队列会不断检查里面的消息,并且只有当当前系统时间到达或超过某条消息的执行时间时,消息才会被处理。
  • Looper 会持续地从消息队列中取出需要执行的消息,交给 Handler 处理。

修改系统时间对延迟消息的影响:

延迟消息的触发时间依赖于系统的当前时间(System.currentTimeMillis()),因此如果在消息被执行之前你修改了系统时间,会产生以下情况:

  1. 将系统时间向前调整(加快)

    • 如果你将系统时间调整为未来的某个时间点,则延迟消息会立即被处理,因为系统认为当前时间已经超出了消息的设定触发时间。
  2. 将系统时间向后调整(减慢)

    • 如果你将系统时间调整为过去的时间,则延迟消息会推迟执行。消息的设定触发时间会大于当前时间,系统会继续等待时间达到指定点再处理。

解决方案:

如果你想避免系统时间更改对延迟任务的影响,可以使用基于相对时间的时间源,例如:

  • SystemClock.uptimeMillis():它表示自设备启动以来的时间,排除了深度睡眠的时间。
  • SystemClock.elapsedRealtime():表示自设备启动以来的时间,包括设备处于休眠状态的时间。

这样做的好处是,系统时间的修改不会影响任务的执行,因为这些方法不依赖系统时间,而是基于设备的持续运行时间。

long delayMillis = 5000;  
handler.postAtTime(runnable, SystemClock.uptimeMillis() + delayMillis);

使用 SystemClock.uptimeMillis()SystemClock.elapsedRealtime() 可以确保你的延迟任务不会因为系统时间的修改而受到影响。

参考:

分析修改系统时间对Handler延迟消息是否有影响

面试:Handler.postDelayed()精确延迟指定时间的原理

www.kancloud.cn/alex_wsc/an…

www.cnblogs.com/jiy-for-you…

mazhuang.org/rtfsc-andro…

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/22601,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?