离子应用程序中的计时器(setInterval)在后台运行一段时间后进入睡眠状态

Timers(setInterval) in ionic apps go to sleep after some time in the background

我的 ionic 应用程序有一个计时器(一个简单的 setInterval,每秒滴答一次),当应用程序位于前台时,它工作得很好。然而,当应用程序进入后台并在 10 分钟后返回前台时,应用程序中显示的时间是错误的(时间比应该的少得多)。我试过将计时器添加到指令中并使用本机 DOM 操作 api(document.getElementById, 等) 方法,但它们都没有用。我认为当应用程序进入后台时,离子框架正在对视图和绑定做一些事情。有没有人遇到过这样的问题,如果遇到过,你们是如何解决的?

Ionic/Cordova 应用程序在后台模式下进入睡眠状态。但是你可以看看这个:https://github.com/katzer/cordova-plugin-background-mode

经过几个小时的寻找答案,我终于想出了自己的 hack。我希望这个解决方案可以帮助遇到类似问题的其他人。

当应用程序进入后台时,在某个随机时间,计时器停止滴答并进入睡眠状态,直到应用程序返回前台。 当应用程序出现在前台时,计时器会从它进入休眠状态的那一刻再次开始计时。

  • Solution/Hack:

    1. 将时间戳记录在一个单独的变量中(以秒为单位),并在计时器的每个时间间隔更新它。

      var timeStamp = Math.floor(Date.now() / 1000);

    2. 如果您之前间隔的时间戳与最新(新)时间戳之间的差异大于一秒,请检查计时器的每个间隔。如果满足条件,将这两个时间戳之间的差异添加到您的滴答时间。

  • 工作原理:

    应用在前台

    1. 就在计时器开始计时之前
      - 记录的时间戳(假设 1 秒)
    2. 计时器开始计时
      - 检查条件 if(currentTimeStamp - previousTimeStamp > 1) { Add the the above difference to the time } Before the interval ends, update the TimeStamp variable with the currentTimeStamp.
      在第一个间隔中,currentTimeStamp 应该是 1 秒或 2 秒,具体取决于您将计时器卸载到 setTimeout 中的天气。 因此,差异肯定是 0 或 1。由于条件不匹配,我们将时间戳更新为 1 或 2 秒,然后继续下一个间隔。 只要计时器不进入休眠状态,我们的条件就会失败。

    后台应用程序

    奇怪的是,10 分钟后,计时器进入休眠状态(我们的计时器实际上正在失去对现在时间的跟踪,因为下一个间隔没有触发)。

    App return 从后台到前台

    计时器从它停止的地方开始计时(即下一个间隔)。现在我们的条件差异应该超过一秒,因此将这个差异(基本上是损失的时间)加到我们当前的滴答时间上。

  • 代码:

    var transactionTime = 0; //Initial time of timer
    var timeStamp = Math.floor(Date.now() / 1000);
    var deltaDelay = 1;
    
    setInterval(function () {
        if (transactionTime != 0 && (Math.floor(Date.now() / 1000) - timeStamp) > deltaDelay) {
                transactionTime += (Math.floor(Date.now() / 1000) - timeStamp);
            }
            timeStamp = Math.floor(Date.now() / 1000);
    
            //Update your element with the new time.
            window.document.getElementById("transaction_timer").innerHTML = util.formatIntoHHMMSS(transactionTime++);
    
        }, 1000);
    

    注意:这个解决方案独立工作(vanilla Js with native DOM api)并且在 angular 指令中也很好用。
    如果您的单个线程有可能在其他地方忙于其他任务,您可以将上述代码的 deltaTime 增加到 2 以更加准确。
    P.s 我实际上 运行 我自己的 webview 实例中的离子应用程序而不是 cordova,所以我不能使用任何花哨的 cordova 插件。

  • 这是来自

    var interval = null;
    var timerSecondsTotal = 0;
    
    function runTimer() {
          var prevTickTimestamp = Date.now()
    
          interval = setInterval(() => {
            var currentTickTimestamp = Date.now()
            var delta = currentTickTimestamp - prevTickTimestamp
    
            timerSecondsTotal += Math.round(delta / 1000)
    
            prevTickTimestamp = currentTickTimestamp
          }, 1000)
        }