multithreadingkotlin-coroutinesandroid-runonuithread

The .join() method block UI thread even when called on a new thread


I was writing a kotin application that needs to retrive data online. Using the async(Dispatcher.IO) to get the result from the server and

val variable1 = async(Dispatchers.IO) {
                         delay(10000)
                         "I am the guy who comes 10 secs later\nDid you miss me?"
                      }

using variable1.join() to wait for the result like shown below:

@ExperimentalCoroutinesApi
    fun btn(view: android.view.View) {
        binding.firstText.text = ""
        runBlocking {
            launch(Dispatchers.IO) {
                //runOnUiThread { pop = popUp() }
                val variable1 = async(Dispatchers.IO) {
                    delay(10000)
                    "I am the guy who comes 10 secs later\nDid you miss me?"
                }
                variable1.join()
                val a = variable1.await()
                Log.d(TAG, "btn: ******************************************************* $a")
                runOnUiThread {
                    //binding.firstText.text = a
                }
            }
        }
    }

I have an issue getting the result asynchronously, variable1 keeps blocking the UI thread. To my understanding, .join() waits for the result before executing. But the problem is that it blocks the UI thread even when its not run on the main thread. How better should I have done this task? Thanks.


Solution

  • Since I see no evidence of any blocking operations, this is all you need:

    fun btn(view: android.view.View) {
        binding.firstText.text = ""
        viewModelScope.launch {
            delay(10_000)
            val a = "I am the guy who comes 10 secs later\nDid you miss me?"
            Log.d(TAG, "btn: $a")
            binding.firstText.text = a
        }
    }
    

    If you do intend to make blocking operations instead of that delay(10_000), then you can add this:

    fun btn(view: android.view.View) {
        binding.firstText.text = ""
        viewModelScope.launch {
            val a = withContext(Dispatchers.IO) {
                blockingOperation()
                "I am the guy who comes 10 secs later\nDid you miss me?"
            }
            Log.d(TAG, "btn: $a")
            binding.firstText.text = a
        }
    }
    

    Note there's the viewModelScope, this won't work unless you're inside a ViewModel class. You can use GlobalScope instead to try things out, but this is not a production-worthy solution as it leads to memory leaks at runtime whenever you trigger many such actions while the previous ones are in progress (and they will be because there's nothing cancelling them).