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

时间:2020-05-31 12:40:01

标签: android kotlin mvvm coroutine

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

我的问题很简单:为什么以下协程似乎不会阻塞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)
                }
            }
        })
    }

这是带有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
}

1 个答案:

答案 0 :(得分:1)

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

  1. dipatcher.IO->网络操作
  2. dispatcher.Main->在主线程上
  3. dispatcher.Default->用于CPU密集型操作

为详细解释您,我以文档中的示例为例:-

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
    } 
}

评论应该说明一切。这将立即打印“ Hello”,并添加“ World!”一秒钟后。 这与处理您的代码相同,挂起函数fetchBusTime()将在不阻塞线程的情况下执行,并且在此方法内完成操作后,它将执行updateUI(it, times)

有关此内容的更多详细信息,请阅读这篇文章here