美文网首页
Hander.sendMessageDelayed()延时消息为

Hander.sendMessageDelayed()延时消息为

作者: feifei_fly | 来源:发表于2021-10-30 22:54 被阅读0次

一、SystemClock 系统时钟类:

SystemClock提供了几种不同的获取时间的方法:

1.1、SystemClock.uptimeMillis 它获取的是系统从开机到现在的时间,单位是毫秒。但是它不包括系统休眠的时间(cpu休眠、屏幕休眠等)

  • System.currentTimeMillis()对应取出的是, 标准挂钟时间(日期+时间),从1970年1月1日 UTC到现在的毫秒数 属于绝对时间。
  • 使用System.currentTimeMillis存在一定的风险,因为它是以系统时间为基准的,而我们可以通过SystemClock.setCurrentTimeMilis来设置系统时间。因此推荐使用SystemClock.uptimeMillis()

SystemClock.setCurrentTimeMillis()可以修系统时钟.
调用setCurrentTimeMillis 需要申请对应的权限。

 /**
     * Sets the current wall time, in milliseconds.  Requires the calling
     * process to have appropriate permissions.
     *
     * @return if the clock was successfully set to the specified time.
     */
    public static boolean setCurrentTimeMillis(long millis) {
        final IAlarmManager mgr = IAlarmManager.Stub
                .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
        if (mgr == null) {
            Slog.e(TAG, "Unable to set RTC: mgr == null");
            return false;
        }

        try {
            return mgr.setTime(millis);
        } catch (RemoteException e) {
            Slog.e(TAG, "Unable to set RTC", e);
        } catch (SecurityException e) {
            Slog.e(TAG, "Unable to set RTC", e);
        }

        return false;
    }

1.2、SystemClock.elapsedRealtime 它获取的是从开机到现在的时间,单位是毫秒。它包括了系统休眠的时间。

   /**
     * Returns milliseconds since boot, including time spent in sleep.
     *
     * @return elapsed milliseconds since boot.
     */
    @CriticalNative
    native public static long elapsedRealtime();

1.3、SystemClock.elapsedRealtimeNanos 它获取的是开机到现在的时间,单位是纳秒。它包括了系统休眠的时间。

1.4、SystemClock.currentThreadTimeMilis

它获取的是在当前线程中运行的时间,单位是毫秒。

二、SystemClock引发的问题:

Hanler中发送消息(或者延时消息) 是通过SystemClock.uptimeMillis()为基准计算的。

2.1、MessageQueue入队列时,计算Message.when以SystemClock.uptimeMillis()时间为基准

 public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

2.2、从MessageQueue中消费Message,判断Message是否到了执行时间,也是以uptimeMillis()为基准

Looper.loop()循环

 public static void loop() {
        for (;;) {
            Message msg = queue.next(); // might block
            msg.target.dispatchMessage(msg);

        }
     }

从MessageQueue中取Message,执行时间也是以SystemClock.uptimeMillis()为基准进行比较的。

msg.when > now时 才会将Message取出然后执行。

    Message next() {


        for (;;) {
           
            ...
            
            synchronized (this) {
              // (1)计算当前时间
              final long now = SystemClock.uptimeMillis();
        
                // 返回取到的Message 
                if (msg != null) {
                    //msg尚未到达触发时间,则计算新的阻塞超时时间nextPollTimeoutMillis,下次循环触发队列阻塞
                    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;
                        msg.markInUse();
                        return msg;
                    }
                } 


                ...
        }

    }

2.3、System.uptimeMillis()计算系统从开机到现在的时间,单位是毫秒。但是它不包括系统休眠的时间(cpu休眠、屏幕休眠等)。

当手机灭屏处于休眠状态的时间是不计算进System.uptimeMillis()

比如发送一个延时20分钟的Message消息,系统灭屏后进入了深度睡眠(假设深度睡眠了1个小时),当进程苏醒后,这一个小时的时间是不计入(1)中的now

  final long now = SystemClock.uptimeMillis();

从系统时钟看 已经过去1个小时了,但是计算now时,因为uptimeMillis 不包含休眠时的时间。

如果now< msg.when,会判定messsage还没有到执行时间,就不会从MessageQueue中取出并执行。

相关文章

  • Hander.sendMessageDelayed()延时消息为

    一、SystemClock 系统时钟类: SystemClock提供了几种不同的获取时间的方法: 1.1、Syst...

  • RabbitMQ进阶

    延时消息 延时消息的两种实现办法 过期消息+死信队列(问题 支持顺序 但是消息的粒度不够) 使用延时消息插件 消息...

  • RocketMQ源码分析----延时消息和重试消息的实现

    延时消息的例子 和普通消息发送没多大区别,只是多了个句设置延时级别的代码 level为3那么代表10s后消费者10...

  • mq延时消息

    原本想写下kafka事务的很多大神都写了,在此引用一篇大佬的文章吧http://www.jasongj.com/k...

  • 延时消息队列

    场景: 用户预约课程,提前1个小时提醒用户 用户会员卡到期,提前提醒 生产者 DelayQueue.php 消费...

  • 延迟消息

    延迟消息延迟消息主要针对生产者延时队列的延时延时时间分为18个级别messageDelayLevel=1s 5s ...

  • spring boot 集成rabbitmq 实现延迟队列

    rabbitmq 实现延迟队列 什么是延迟队列 延迟队列存储的对象肯定是对应的延时消息,所谓”延时消息”是指当消息...

  • 使用 Kotlin+RocketMQ 实现延时消息

    一. 延时消息 延时消息是指消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进...

  • RabbitMQ实现延迟消费(延迟队列)

    什么是延迟队列延迟队列存储的对象是对应的延时消息,所谓”延时消息”是指当消息被发送以后,并不想让消费者立即拿到消息...

  • RabbitMQ 延时插件实现消息延时发送

    起因:在实际项目开发过程中,需要使用RabbitMQ来实现消息队列的功能,但仅仅实现功能之后并不能对自己满足,既然...

网友评论

      本文标题:Hander.sendMessageDelayed()延时消息为

      本文链接:https://www.haomeiwen.com/subject/kcmnaltx.html