androidmultithreadingkotlinandroid-runonuithread

Multi-thread runOnUiThread


I have a need to update the UI from a thread. In doing so, I created a Toast message to test that the function was working as expected. While in my thread, I run the function "runOnUiThread" and inside this function I place a Toast message, like this...

runOnUiThread {
    Toast.makeText(this, "DIALOG Start", Toast.LENGTH_SHORT).show()
}

Although this does work, it also doesn't work. The Toast message stays on the device screen. I have tested it both on emulator and live device. Every time I run the code, the Toast message stays on the screen.

However, if I separate the toast message as an extension type function, it works as expected.

val toast = Toast.makeText(this@MainActivity, "Dialog finish", Toast.LENGTH_SHORT)

runOnUiThread {
    toast.show()
}

This works as expected.

I am wondering, why? Both sets of code call runOnUiThread(). Both are calling a Toast message. What is the difference in the two?

Is this a product of using Kotlin and updating UI and updating from a Thread? Is this because the thread is not stopped? Will the Toast go away if I call

thread.stop() Although it is deprecated.

This is the code that works:

progressDoalog!!.max = 100
val toast = Toast.makeText(this@MainActivity, "Dialog finish", Toast.LENGTH_SHORT)
Thread {
   try {
        while (progressDoalog!!.progress <= progressDoalog!!.max) {
        Thread.sleep(50)
        handle.sendMessage(handle.obtainMessage())
        if (progressDoalog!!.progress == progressDoalog!!.max) {
        progressDoalog!!.dismiss()
        runOnUiThread {
           toast.show()
        }
    }
  }
 } catch (e: Exception) {
       e.printStackTrace()
 }
}.start()

Solution

  • The cause of the problem is more clear if you fix your indentation:

    val toast = Toast.makeText(this@MainActivity, "Dialog finish", Toast.LENGTH_SHORT)
    Thread {
        try {
            while (progressDoalog!!.progress <= progressDoalog!!.max) {
                Thread.sleep(50)
                handle.sendMessage(handle.obtainMessage())
                if (progressDoalog!!.progress == progressDoalog!!.max) {
                    progressDoalog!!.dismiss()
                    runOnUiThread {
                        toast.show()
                    }
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }.start()
    

    This while loop runs forever. Once progress is equal to max, you start showing the toast over and over. Your conditional for the while loop will still be true forever, so it never stops calling show() on your Toast.

    In your non-working code, you were creating a new Toast on every iteration of the loop, so once one toast goes away, there's another identical one behind it.

    In your "working" code, you are calling show() on the same Toast instance over and over, so it only appears once. However, you will have leaked an immortal thread.