离子应用程序中的计时器(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:
将时间戳记录在一个单独的变量中(以秒为单位),并在计时器的每个时间间隔更新它。
var timeStamp = Math.floor(Date.now() / 1000);
如果您之前间隔的时间戳与最新(新)时间戳之间的差异大于一秒,请检查计时器的每个间隔。如果满足条件,将这两个时间戳之间的差异添加到您的滴答时间。
工作原理:
应用在前台
- 就在计时器开始计时之前
- 记录的时间戳(假设 1 秒)
- 计时器开始计时
- 检查条件
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)
}
我的 ionic 应用程序有一个计时器(一个简单的 setInterval,每秒滴答一次),当应用程序位于前台时,它工作得很好。然而,当应用程序进入后台并在 10 分钟后返回前台时,应用程序中显示的时间是错误的(时间比应该的少得多)。我试过将计时器添加到指令中并使用本机 DOM 操作 api(document.getElementById, 等) 方法,但它们都没有用。我认为当应用程序进入后台时,离子框架正在对视图和绑定做一些事情。有没有人遇到过这样的问题,如果遇到过,你们是如何解决的?
Ionic/Cordova 应用程序在后台模式下进入睡眠状态。但是你可以看看这个:https://github.com/katzer/cordova-plugin-background-mode
经过几个小时的寻找答案,我终于想出了自己的 hack。我希望这个解决方案可以帮助遇到类似问题的其他人。
当应用程序进入后台时,在某个随机时间,计时器停止滴答并进入睡眠状态,直到应用程序返回前台。 当应用程序出现在前台时,计时器会从它进入休眠状态的那一刻再次开始计时。
Solution/Hack:
将时间戳记录在一个单独的变量中(以秒为单位),并在计时器的每个时间间隔更新它。
var timeStamp = Math.floor(Date.now() / 1000);
如果您之前间隔的时间戳与最新(新)时间戳之间的差异大于一秒,请检查计时器的每个间隔。如果满足条件,将这两个时间戳之间的差异添加到您的滴答时间。
工作原理:
应用在前台
- 就在计时器开始计时之前
- 记录的时间戳(假设 1 秒) - 计时器开始计时
- 检查条件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)
}