[英]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.