如何使用流程协程创建倒计时

Stu*_*DTO 3 android kotlin kotlin-coroutines kotlinx.coroutines.flow

我正在尝试使用协程创建一个流程,但它没有给我预期的结果。我想要的是给出一个过期时间(无论是否以毫秒、秒等为单位都没关系),当时间到达 0 时,它会停止倒计时。我现在拥有的是:

private fun tickerFlow(start: Long, end: Long = 0L) = flow {
        var count = start
        while (count >= end) {
            emit(Unit)
            count--
            delay(1_000L)
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后我将此函数称为:

val expireDate = LocalDateTime.now().plusSeconds(10L).toEpochSecond(ZoneOffset.UTC)
                tickerFlow(expireDate)
                    .map { LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) - expireDate }
                    .distinctUntilChanged { old, new ->
                        old == new
                    }
                    .onEach {
                        //Here I should print the timer going down with this pattern 
                        //00h: 00m: 00s I did it with String.format("%02dh: %02dm: %02ds") and it works though.
                    }
                    .onCompletion {
                        //Setting the text when completed
                    }
                    .launchIn(scope = scope)
Run Code Online (Sandbox Code Playgroud)

但即使通过这个测试,我试图将到期时间设置为从现在起 10 秒,它也不会像我想的那样打印或结束。我错过了什么吗?有什么办法可以发出本地日期时间,这样我就有小时、分钟和秒吗?也许我必须进行微积分才能从毫利斯/秒中得到秒、分钟、小时。

太长了;

我从后端得到一个到期日期,我想知道这个到期日期何时结束,所以我必须使用 now() 计算它并检查它何时到期。

Arp*_*kla 7

你在这里真的不需要流量。试试这个代码:

val expireDate = LocalDateTime.now().plusSeconds(10L).toEpochSecond(ZoneOffset.UTC)
val currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)
for (i in (expireDate - currentTime)  downTo 1) {
    println("$i seconds remaining") // Format the remaining seconds however you wish
    delay(1_000) // Delay for 1 second
}
println("TIME UP") // Run your completion code here
Run Code Online (Sandbox Code Playgroud)

此外,该代码可以安全地在主线程上运行,因为delay不会阻塞。

在您的代码中,问题在于您将其expireDate自身传递给tickerFlow. expireDate包含从纪元开始的时间(以秒为单位),而不是与当前时间的秒差。只需传递expireDate - LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)给tickerFlow 就可以了。

编辑:使用流程完成实现

private fun tickerFlow(start: Long, end: Long = 0L) = flow {
    for (i in start downTo end) {
        emit(i)
        delay(1_000)
    }
}
Run Code Online (Sandbox Code Playgroud)
val expireDate = LocalDateTime.now().plusSeconds(10L).toEpochSecond(ZoneOffset.UTC)
val currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)
tickerFlow(expireDate - currentTime)
    .onEach { secondsRemaining ->
        // Format and display the time
    }
    .onCompletion { 
        // Handle completion
    }
    .launchIn(scope)
Run Code Online (Sandbox Code Playgroud)