在延迟时间内重复执行任务

时间:2019-04-10 07:00:32

标签: android kotlin kotlin-coroutines

我必须在一个时间范围内(例如6秒内)移动进度条。我正在使用协程和“重复”功能。除了总执行时间未指定之外,该代码将执行。下面是我的代码。

val progressJob = Job()
var startTime = 0L
CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()
    repeat(1000) {
        progressBar.progress += 1
        delay(6)
    }
    Log.d(TAG, "total time= ${System.currentTimeMillis() - startTime}")
}

我期望“总时间”为6000,但是我得到的值大于6000至少500。

基本上,我只想在一个时间范围内重复增加进度条,由于性能问题,我不使用动画。

有什么我想念的吗?

4 个答案:

答案 0 :(得分:2)

我会这样处理:

withTimeout(1300L) {
    repeat(1000) { i ->
        println("Blip Blop $i ...")
        delay(500L)
    }
}

有关更多示例,请参见官方文档: https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html

答案 1 :(得分:0)

协程不提供精确的时间。如果处理器忙于同时运行其他程序,协程很容易被延迟。使用Timer Class获得准确的时间。这是一个例子。我每秒钟记录一次时间,并在6秒后取消计时器。结果仅相差几毫秒。

    var startTime = 0L
    val timer : Timer = Timer()
    val task = object : TimerTask()
    {
        var lastTime = 0L
        override fun run() {
            val now = System.currentTimeMillis()
            if(now/1000 > lastTime/1000 )
            {
                Log.d("timer","total time= ${now - startTime}")
                lastTime = now
            }
            if(now - startTime >= 6000)
            {
                timer.cancel()
            }
    }
    startTime = System.currentTimeMillis()
    timer.scheduleAtFixedRate(task,0,6)

答案 2 :(得分:0)

所以您在这里正在模拟进度。理想情况下,可以使用某种方法来检查栏的实际进度,并进行更新,完成后结束。但是,如果不可能,那么,模拟是您的选择。

因此,使用协程,我们正在处理线程环境,并且在其中,我们拥有协程,当移交执行控制时,这些协程需要继续。在您的实现中,此操作发生在delay调用中。因此,很难保证协程会在所需时间内完成。所有延迟都可以做,就是说它不会在“至少”经过指定的时间之前恢复,并且可能经常会经过更多的时间,而不是确切的时间。

那么,我们如何使它在尽可能接近您期望的时间范围内执行?我们需要做的是丢弃repeat,而是检查经过的时间来确定是否完成。这是一个粗略的实现,希望会对您有所帮助。

class Bar(val barLength: Int = 1000) {
    var progress = 0
}

suspend fun simulateProgress(bar: Bar, job: Job, totalDurationMillis: Long, incrementsMills: Long): Job {
    var startTime = System.currentTimeMillis()
    return CoroutineScope(Dispatchers.Default + job).launch {
        var totalElapsed = 0L
        while (totalElapsed < totalDurationMillis) {
            totalElapsed = System.currentTimeMillis() - startTime
            val progressRatio = totalElapsed.toDouble()/totalDurationMillis.toDouble()
            bar.progress = (progressRatio * bar.barLength.toDouble()).toInt()
            delay(incrementsMills)
        }
        println("Elapsed: $totalElapsed, Progress: ${bar.progress}")
    }
}

fun main() = runBlocking {
    val job = Job()
    val bar = Bar()
    val progressJob = simulateProgress(bar, job, 6000, 10)
    progressJob.join()
} 

答案 3 :(得分:0)

您不仅在测量6毫秒的延迟,而且在测量执行for循环(隐藏在repeat中所需的时间,加上progressBar.progress += 1的时间和成本) delay本身。

例如:

CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()
    repeat(1000){
        delay(6)
    }
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}

我的机器上需要6751毫秒(平均100次运行)。

如果我使用Thread.sleep而不是延迟:

CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()
    repeat(1){
        delay(6)
    }
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}

花费6701ms。

如果我执行一次,请重复一次:

CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()
    repeat(1){
        Thread.sleep(6)
    }
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}

8ms

如果我删除重复:

CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()         
    Thread.sleep(6)
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}