【发布时间】:2020-05-31 12:40:01
【问题描述】:
我对 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
}
【问题讨论】:
-
您是否阅读过任何有关协程是什么的文档?挂起函数永远不会阻塞主线程(只要它们编写正确)。它们暂停协程的执行(在主线程的情况下,它可以释放它来执行 UI 所需的任何其他操作),直到它们返回。
-
是的,我读过它。问题是,将协程放入 dipatcher.IO 或 Dispatcher.default 有什么意义?我认为视频让我意识到我的代码中发生了什么。在主线程中启动协程时,当 Retrofit 被调用时,Retrofit 会自动切换上下文。有意义吗?
-
任何正确编写的挂起函数都会在运行阻塞代码时从主调度器切换。简单挂起函数的常用习惯用法是
suspend fun x(param: Int) = withContext(Dispatchers.IO) { /* some blocking code */ }。不调用任何阻塞代码的挂起函数,仅调用其他挂起函数和非阻塞函数,不需要显式更改调度程序。
标签: android kotlin mvvm coroutine