LifecycleScope 中的 Kotlin 协程不会阻塞主线程

Nin*_*ski 6 android mvvm coroutine kotlin

我对 ViewModel 中的协程感到困惑。

我的问题很简单:为什么下面的协程看起来没有阻止 UIThread?(协程运行时UI依然流畅)

我的片段就在这里:

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)
                }
            }
        })
    }
Run Code Online (Sandbox Code Playgroud)

这是使用 fetchBusTime 方法拍摄的 ViewModel:

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
}
Run Code Online (Sandbox Code Playgroud)

Sha*_*T D 3

launch允许我们在后台启动协程并同时继续工作。Suspending函数可以挂起当前协程的执行而不阻塞当前线程。我们可以在以下任何调度程序下启动协程。

\n
    \n
  1. dipatcher.IO -> 网络操作
  2. \n
  3. Dispatcher.Main -> 在主线程上
  4. \n
  5. Dispatcher.Default -> 用于 CPU 密集型操作
  6. \n
\n

为了详细解释你,我从文档中举了一个例子:-

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

评论应该不言而喻。这将立即打印 \xe2\x80\x9cHello,\xe2\x80\x9d,并在一秒钟后添加 \xe2\x80\x9cWorld!\xe2\x80\x9d。\n这与你的代码相同,挂起函数fetchBusTime()将在不阻塞线程的情况下执行,并且在该方法内的操作完成后,它将执行updateUI(it, times)

\n

有关这方面的更多详细信息,请在此处阅读这篇文章

\n