美文网首页
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()延时消息为

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