美文网首页
Handler.postDelay()的坑

Handler.postDelay()的坑

作者: FreedApe | 来源:发表于2018-11-23 15:46 被阅读0次

    现在某些app,当你进入后台(BG)的情况下,过了特定的时间段,再从后台切换回来,就会在原来的页面上显示一个广告页面或者解锁页面或者其他特定的页面。

    刚开始,我使用Handler.postDelay()的方式来实现这种效果,代码如下(也是参考别人的方法):

    public class BaseApplication extends Application implements Application.ActivityLifecycleCallbacks {
    
        private boolean foreground;
        private boolean paused = true;
        private Handler handler = new Handler();
        private Runnable check;
    
        private Long pausedTime = 0L;
        private Long resumedTime = 0L;
    
        ....
    
        @Override
        public void onActivityResumed(Activity activity) {
            paused = false;
            boolean wasBackground = !foreground;
            foreground = true;
            if (check != null) {
                handler.removeCallbacks(check);
            }
    
            resumedTime = System.currentTimeMillis();
            LogUtils.outputLog("Test resumeTime " + resumedTime);
            LogUtils.outputLog("Test duration Time  " + (resumedTime - pausedTime));
    
            if (wasBackground) {
               // 显示特定页面
            }
        }
    
        @Override
        public void onActivityPaused(Activity activity) {
    
            paused = true;
            if (check != null) {
                handler.removeCallbacks(check);
            }
    
            pausedTime = System.currentTimeMillis();
    
            long delayTime = 1000 * 60;
            handler.postDelayed(check = () -> {
                if (foreground && paused) {
                    foreground = false;  // app 在 BG 经过 1min 后,正常来说是应该触发这里。
                }
            }, delayTime);
        }
    }
    
    

    这段代码 在设备亮屏或者连接USB锁屏的情况下是没有问题的。

    但是

    当设备没有连接USB处于锁屏状态下,就出问题了.......postDelay 里面的 runnable 不会执行。

    查看了Handler.postDelay的源码,如下:

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

    发现是在 SystemClock.uptimeMillis() + delayMillis 时间点发送 msg,如果 SystemClock.uptimeMillis() 在特殊情况下,出现问题,这个msg 就不会发送出来了。

    SystemClock.uptimeMillis()的源码:

        /**
         * Returns milliseconds since boot, not counting time spent in deep sleep.
         *
         * @return milliseconds of non-sleep uptime since boot.
         */
        @CriticalNative
        native public static long uptimeMillis();
    

    注意这个方法的注释:Returns milliseconds since boot, not counting time spent in deep sleep.
    说的是睡眠模式下的时间不会进行计算。

    我在onActivityResumed和onActivityPaused 分别对SystemClock.uptimeMillis()进行 log 输出,如果要显示解锁页面,SystemClock.uptimeMillis() + delayMillis应该是大于 10836078 + 60000 = 10896078,但是实际当时间过去3min后,却是10872205

    11-15 15:59:05.829 25137-25137/YourAppName: Test PausedTime 1542265145829
    11-15 15:59:05.829 25137-25137/YourAppName: Test time(onActivityPaused):10836078-->SystemClock.uptimeMillis()
    11-15 16:04:52.218 25137-25137/YourAppName: Test resumeTime 1542265492217
    11-15 16:04:52.218 25137-25137/YourAppName: Test time(onActivityResumed):10872205-->SystemClock.uptimeMillis()
    11-15 16:04:52.218 25137-25137/YourAppName: Test duration Time  346388
    

    所以handler.postDelay不是 所有情况下都合适的。对之前的代码进行了改动:

    public class BaseApplication extends Application implements Application.ActivityLifecycleCallbacks {
    
        private Long pausedTime = 0L;
        private Long resumedTime = 0L;
    
        @Override
        public void onActivityResumed(Activity activity) {
            resumedTime = System.currentTimeMillis();
            boolean wasBackground = false;
            long delayTime = 1000 * 60;
            if ((resumedTime - pausedTime) > delayTime) {
                wasBackground = true;
            }
    
            if (wasBackground) {
            .....
            }
        }
    
        @Override
        public void onActivityPaused(Activity activity) {
            pausedTime = System.currentTimeMillis();
        }
    }
    

    以上。

    相关文章

      网友评论

          本文标题:Handler.postDelay()的坑

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