Flow.collect 阻塞主线程

use*_*079 6 multithreading android kotlin kotlin-coroutines kotlin-flow

我的以下代码似乎阻塞了主线程,即使该流程是在 IO 协程上调用的。我是一个 kotlin 和 flow 菜鸟。我在这里做错了什么导致主线程阻塞?

存储库:

fun observeData(): Flow<Data> {
  return flow {
     //third party api is getting data from a ContentProvider
     ThirdPartyApi.getData().map { convertFromExternalModelToDataModel(it) }
     .collect {
         emit(it)
     }
  }
}
Run Code Online (Sandbox Code Playgroud)

视图模型:

fun updateUI() {
   scope.launch(Dispatchers.IO) {
     repository.observerData().collect {
       withContext(Dispatchers.Main) {
          textView.text = data.name
       }
     }
   }
}
Run Code Online (Sandbox Code Playgroud)

运行以下代码后,我看到来自 Android Choreographer 的日志“跳过 200 帧。应用程序在主线程上工作太多”

Sov*_*ong 10

要使用 Kotlin Flows 收集发出的数据流,请使用collect。并作为collect一个挂起函数,它需要在协程中执行。它采用 lambda 作为参数,在每个新值上调用该参数。由于它是一个挂起函数,因此调用collect的协程可能会挂起,直到流程关闭。

\n

而且您不应该在 ViewModel 内更新 UI。

\n

在这种情况下,我们收集活动生命周期范围内的流,该范围是主要安全的并且具有活动生命周期意识。

\n

为了使我们的服务或存储库在不同的环境中执行CouroutineContext,请使用中间操作符flowOn

\n

flowOn更改CoroutineContext上游流的 ,意味着生产者和之前(或之上)应用的任何中间操作符flowOn

\n

下游流(flowOn与消费者一起的中间操作符)不受影响,并在CoroutineContext用于从流中收集的数据上执行。

\n

视图模型:

\n
fun getData():Flow<Data> = repository.observeData() // Execute on the io dispatcher\n// flowOn affects the upstream flow \xe2\x86\x91\n.flowOn(Dispatchers.IO)\n// the downstream flow \xe2\x86\x93 is not affected\n.catch { exception -> // Executes in the consumer's context\n    emit(Data())\n}\n
Run Code Online (Sandbox Code Playgroud)\n

活动:

\n
override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    \n    lifecycleScope.launch { // Consumer's context\n        viewModel.getData().collect { // Suspended\n            textView.text = data.name // Collect on consumer's context\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n