[英]How can I implement a timer in a portable way in Jetpack Compose?
我想编写一些应用程序,其中我希望某些事情按计划发生。
每隔几分钟轮询一次 URL 更新似乎是一个相当常见的用例。 不过,在这种特殊情况下,我只是想实现一个时钟。
这有效:
@Composable
fun App() {
var ticks by remember { mutableStateOf(0) }
// Not 100% happy about this unused variable either
val timer = remember {
Timer().apply {
val task = object : TimerTask() {
override fun run() {
ticks++
}
}
scheduleAtFixedRate(task, 1000L, 1000L)
}
}
MaterialTheme {
Text(
// A real application would format this number properly,
// but that's a different question
text = "$ticks"
)
}
}
但我必须导入java.util.Timer
,所以它不会是可移植的。
Jetpack Compose 可以做动画,所以它肯定在某处有自己的计时器,这意味着也应该有一些可移植的方法来做到这一点,但我似乎无法弄清楚。
有没有一种跨平台的方法可以为此目的获取计时器?
在 Compose 中,您可以使用LaunchedEffect
- 它是在协程作用域上运行的副作用,因此您可以在内部使用delay
,如下所示:
var ticks by remember { mutableStateOf(0) }
LaunchedEffect(Unit) {
while(true) {
delay(1.seconds)
ticks++
}
}
我只是想分享一个我尝试过的替代方案,以防其他人想到它并遇到我遇到的相同问题。 这是天真的实现:
@Composable
fun Countdown(targetTime: Long, content: @Composable (remainingTime: Long) -> Unit) {
var remainingTime by remember(targetTime) {
mutableStateOf(targetTime - System.currentTimeMillis())
}
content.invoke(remainingTime)
LaunchedEffect(remainingTime) {
delay(1_000L)
remainingTime = targetTime - System.currentTimeMillis()
}
}
假设您想要精确到一秒,此代码段将导致LaunchedEffect
在更新remainingTime
后更新一秒,更新与当前时间相关的remainingTime
(以毫秒为单位)。 这基本上创建了一个循环。 将此逻辑包装在@Composable
中很好,因为它可以防止在大型组件树中嵌入LaunchedEffect
时可能导致的过度重新组合。
这行得通,但有一个问题:您最终会注意到您的计时器正在跳秒。 发生这种情况是因为在将新值分配给remainingTime
变量和重新执行LaunchedEffect
之间会有一些额外的延迟,这实际上意味着更新之间有超过一秒的时间。
这是上述内容的改进实现:
@Composable
fun Countdown(targetTime: Long, content: @Composable (remainingTime: Long) -> Unit) {
var remainingTime by remember(targetTime) {
mutableStateOf(targetTime - System.currentTimeMillis())
}
content.invoke(remainingTime)
LaunchedEffect(remainingTime) {
val diff = remainingTime - (targetTime - System.currentTimeMillis())
delay(1_000L - diff)
remainingTime = targetTime - System.currentTimeMillis()
}
}
我们只需从预期的延迟时间中减去LaunchedEffect
重新执行所花费的时间。 这将避免您的计时器跳过秒数。
额外的延迟不应该成为已接受答案中实施的问题。 我注意到这种方法的唯一优点是,一旦我们离开屏幕,循环就会停止运行。 在我的测试中,当导航到另一个 Activity 时,具有true
条件的 while 循环继续运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.