如何在 Kotlin 中使用 Thread.sleep()

How to use Thread.sleep() in Kotlin

这来自此处找到的代码实验室接近尾声:

Intro to debugging - Debugging example: accessing a value that doesn't exist

这些都在 MainActivity.kt 文件中

这是我的 onCreate

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val helloTextView: TextView = findViewById(R.id.division_textview)
    helloTextView.text = "Hello, debugging!"

    division()
}
//...

这里是Google提供的除法函数,但是有2个变化我稍后会解释...

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

说明看起来他们希望 sleep() 接受秒,但 AS 表示它需要毫秒,所以我将他们的 3 更改为 3000。我添加了 Log.v(TAG, "${numerator / denominator}") 以查看发生了什么,因为它没有按预期进行。

这样做的目的是让模拟器创建正在更新的商的 gif。这应该对调试有帮助。

repeat() 完成之前,屏幕上不会显示任何内容,甚至应用程序的名称也不显示。 正如预期的那样,日志以 3 秒为间隔发生。

为什么布局在等待,我如何让它在循环的每次迭代中更新?

老实说,根据他们提供的代码,我不知道 Codelab 在做什么。该应用程序不会在 onCreate 完成之前呈现任何内容(不是布局,也不会对布局进行任何更改),并且 onCreate 直到它的所有代码 运行 才会完成,在它调用的 division 函数中包含 repeat 块。

division 没有启动任何工作线程,所以 Thread.sleep 所做的只是阻塞主线程 - 它正在挂起应用程序。你是对的,sleep 确实采用毫秒值,而不是秒 - 我感觉他们实际上并没有 运行 这段代码,它充满了其他错误和不一致,老实说很难弄清楚你打算做什么。更改哪个 Log.d 调用? onCreate 中的那些? (他们实际上是指 division 中的 Log.v 调用, 我假设


这是在 Kotlin 中使用线程的方法 - 您需要创建一个新线程(这样您就离开了主线程,因此它实际上可以完成创建 activity 和 运行 UI):

fun division() {
    // create a new thread (and start it immediately)
    thread(start=true) {
        repeat(4) { i ->
            Thread.sleep(3000L)
            // assuming you've done the ``findViewById`` and assigned it to a variable
            runOnUiThread { divisionTextView.text = "$i" }
        }
    }
}

为了简洁起见,这只是用当前的重复次数 (i) 进行更新,但重要的是:

  • 您正在创建一个新线程来完成工作(并休眠)
  • 您正在使用 runOnUiThread(这是 Activity 上的一种方法)在 main/UI 线程 上进行文本更新 (一样)。如果您尝试从另一个线程 触摸 UI 它会崩溃

另一种方法是 post 一个 运行nable 通过视图进入 UI 线程,也可以使用 TextView:

divisionTextView.post { divisionTextView.text = "$i" }

协程在这里会是一个更好的主意(你可以 运行 它们在主线程上而不被阻塞,所以你不必担心切换线程来更新 UI,或者任何线程安全的东西)但这是做线程的基础。真的不知道那个代码实验室里发生了什么。

您可以使用协程。延迟功能非常好用

lifecycleScope.launch {
    myTextView.text = "Starting"
    delay(1000L)
    myTextView.text = "Processing"
    delay(2000L)
    myTextView.text = "Done"
}

Nothing displays on screen, not even the app's name, until the repeat() finishes. The logs happen in 3 second intervals, as expected. Why is the layout waiting?

这是由于Activity life cycle

  • 当activity处于Created状态时,您看不到UI。
  • 当 activity 处于 Started 状态时,UI 变为可见但您无法与其交互。
  • 当 activity 处于恢复状态时,UI 可见并且您可以与之交互。

由于您在 onCreate() 回调中调用 division() 函数,因此您不会看到 activity UI.

how do I make it update on each iteration of the loop?

一种方法是 运行 在新线程中执行 division() 函数。通过这样做,主要胎面显示 UI(您将看不到它)。然后使用 运行OnUiThread 更新您的 division_textview 文本。

    fun division() {
    val numerator = 60
    var denominator = 4
    thread(start=true) {
        /* The loop only repeat 4 times to avoid a crash*/
        repeat(4) {
            Log.v(TAG, "$denominator")
            // Set division_textview text to the quotient.
            runOnUiThread { findViewById<TextView>(R.id.division_textview).setText("${numerator / denominator}") }
            // Wait for 1 second
            Thread.sleep(1000L)
            denominator--
        }
    }
}