Kotlin coroutine in lifecycleScope doesn't block main thread

Viewed 2028

I am confused about coroutines in ViewModels.

My question is pretty simple: why does it seem like the following coroutine doesn't block UIThread? (UI is still smooth while coroutine is running)

My fragment right here:

class FragmentSeePaths : Fragment(R.layout.fragment_see_paths),
        PathRecyclerAdapter.OnSetPathForWidgetListener {
    private val pathViewModel: PathViewModel by activityViewModels()
    private lateinit var binding: FragmentSeePathsBinding
    private lateinit var listener: OnAddLineRequestListener

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
    }

    private fun observeWidgetPath() {
        pathViewModel.getUserWidgetPath().observe(viewLifecycleOwner, Observer {
            if (it != null) {
                lifecycleScope.launch {
                    val times = pathViewModel.fetchBusTime(it)
                    updateUI(it, times)
                }
            }
        })
    }

And here are the shotened ViewModel with the fetchBusTime method:

suspend fun fetchBusTime(path: Path): Pair<List<Time>?, List<Time>?> {
        Log.v("fetchBusTimeUI", Thread.currentThread().name) // Main

        // Some network requests made with Retrofit
        val timesResponseStartPoint: GinkoTimesResponse? = repository.getTimes(
                path.startingPoint.startName,
                path.line.lineId,
                path.isStartPointNaturalWay
        )

        val timesResponseEndPoint: GinkoTimesResponse? = repository.getTimes(
                path.endingPoint.endName,
                path.line.lineId,
                path.isStartPointNaturalWay
        )

        return timesResponseStartPoint to timesResponseEndPoint
}
1 Answers

launch allows us to start a coroutine in the background and keep working in the meantime. Suspending functions may suspend the execution of the current coroutine without blocking the current thread. We can start a coroutine under any of the below dispatchers.

  1. dipatcher.IO -> Network operation
  2. dispatcher.Main -> On main thread
  3. dispatcher.Default -> for CPU intensive operation

To explain you in detail, I am taking an example from the documentation :-

fun main() { 
    GlobalScope.launch { // launch new coroutine in background and continue
        delay(1000L)
        println("World!")
    }
    println("Hello,") // main thread continues here immediately
    runBlocking {     // but this expression blocks the main thread
        delay(2000L)  // ... while we delay for 2 seconds to keep JVM alive
    } 
}

The comments should speak for themselves. This will print “Hello,” immediately, and add “World!” after a second. This is the same thing that will work with your code, the suspend function fetchBusTime() will be executed without blocking the thread and after the operation completed inside this method, it will execute updateUI(it, times).

For more details on this please go through this article here

Related