为什么我的代码不更新屏幕上的数字



该函数的作用是将分子与分母相除,并在每隔一秒更新应用程序的文本视图,问题是它不更新屏幕,它只是简单地显示分子的原始数字60。我要做什么改变才能使它工作?

fun division() {
val numerator = 60
var denominator = 4
repeat(4) {
Thread.sleep(1_000)
findViewById<TextView>(R.id.division_textview).setText("${numerator / denominator}")
denominator--
}
}

因为你是设置(基本上覆盖)文本每次循环,你将只看到最后的增量值,这将是60/1,这就是为什么你只看到60值。试试这样:

fun division() {
val numerator = 60
var denominator = 4
repeat(4) {
Thread.sleep(1_000)
findViewById<TextView>(R.id.division_textview).append("${numerator / denominator}n")
denominator--
}
}

setText()用新文本覆盖文本,但append()将保留以前的文本。

这又是那个该死的Codelab,不是吗?我知道它看起来很眼熟……我已经在这里回答了一个类似的问题-但基本上,当你在主线程上运行division时(你必须因为你正在扰乱UI组件),你正在冻结应用程序,因为你正在用Thread.sleep阻塞线程

显示实际上不能更新,直到你的代码已经完成运行,即在你退出division函数之后,因为它都在同一个线程上运行,并且显示更新传递之后。下面是实际情况:

  • 冻结应用1秒
  • 将文本设置为60 / 4的结果-它实际上不会重新绘制,直到稍后,在您的代码完成后,所以没有视觉变化
  • 冻结应用程序1秒
  • 将文本设置为60 / 3的结果-同样,你不会看到任何事情发生,但现在它将显示60 / 3而不是60 / 4,因为你刚刚更新了TextView的状态
  • 等。

您设置的最后一个文本是60 / 1的结果,然后然后您的代码完成,因此系统最终可以开始更新显示。所以在应用程序停止冻结后,你看到的第一个东西是60——它不仅仅是分子,它是循环的最后一个计算。

如果你想在应用程序运行时更新一些东西,有很多解决方案,如协程,CountdownTimers,posting在特定时间执行的可运行程序等。我链接的答案显示了如何创建一个单独的线程来运行基本相同的代码,所以你可以在不影响应用程序运行的情况下尽可能多地阻塞它。你做的一件事是阻塞主线程,就像Codelab示例所做的那样。这是一个糟糕的Codelab

您可以使用delay,然后从协程调用:

private suspend fun division() {
val numerator = 60
var denominator = 4
repeat(4) {
delay(1000)
findViewById<TextView>(R.id.division_textview).text = "${numerator / denominator}"
denominator--
}
}

然后从你的活动/片段:

lifecycleScope.launch {
division()
}

最新更新