I have implemented a timer in Jetpack Compose. Finally it works fine, now. But I'm asking myself if I use Coroutine dispatchers correct.
Here's my code:
@SuppressLint("SimpleDateFormat")
fun formatTime(time: Long): String {
return SimpleDateFormat("mm:ss").format(Date(time * 1000))
}
@Composable
fun TimerScreen(modifier: Modifier = Modifier) {
val initTime = 30 L
var startedAt by remember {
mutableLongStateOf(System.currentTimeMillis())
}
var remainingTime by remember {
mutableLongStateOf(initTime)
}
var isRunning by remember {
mutableStateOf(false)
}
var progress by remember {
mutableFloatStateOf(1.0 f)
}
LaunchedEffect(key1 = startedAt) {
withContext(Dispatchers.IO) {
while (remainingTime > 0) {
if (isRunning) {
delay(1000)
withContext(Dispatchers.Main) {
remainingTime -= 1
progress -= 0.03333334 f
}
}
}
}
}
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Box(contentAlignment = Alignment.Center) {
CircularProgressIndicator(
progress = {
progress
},
modifier = Modifier.size(160. dp),
color = Color.Green,
strokeWidth = 12. dp,
trackColor = Color.LightGray
)
}
Spacer(modifier = Modifier.height(10. dp))
Text(text = formatTime(remainingTime),
fontSize = 32. sp, fontWeight = FontWeight.Bold)
Spacer(modifier = Modifier.height(20. dp))
Row {
IconButton(onClick = {
isRunning = !isRunning
}, modifier = Modifier, enabled = remainingTime > 0) {
val icon =
if (isRunning)
R.drawable.pause_icon
else
R.drawable.play_icon
Icon(painter = painterResource(id = icon),
modifier = Modifier.size(50. dp),
contentDescription = "")
}
IconButton(onClick = {
remainingTime = initTime
startedAt = System.currentTimeMillis()
isRunning = false
progress = 1.0 f
}) {
Icon(painter = painterResource(id = R.drawable.refresh_icon),
modifier = Modifier.size(50. dp),
contentDescription = "")
}
}
}
}
Is my usage of LaunchedEffect correct? Or should I use something else?
Is my Dispatchers-usage correct?
Switching to IO was necessary. Running it from Main crashed the app. I switch back to Main, because I'm not sure, if it is a good idea to update the data from a background-thread. A data-update from a background-thread might lead to problems? What's your opinion?
Looking forward to reading your comments and answers.