Flow.collect 阻塞主线程
Flow.collect blocking the main thread
我有以下代码似乎阻塞了主线程,即使在 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)
}
}
}
ViewModel:
fun updateUI() {
scope.launch(Dispatchers.IO) {
repository.observerData().collect {
withContext(Dispatchers.Main) {
textView.text = data.name
}
}
}
}
根据 运行 下面的代码,我看到来自 Android Choreographer 的日志“跳过 200 帧。应用程序在主线程上工作太多”
要在数据流发出时使用 Kotlin Flows 收集数据流,请使用 collect
。而由于collect
是一个挂起函数,需要在协程中执行。它采用 lambda 作为参数,在每个新值上调用。由于它是一个挂起函数,调用 collect 的协程可能会挂起,直到流程关闭。
而且您不应该在 ViewModel 中更新 UI。
在这种情况下,我们在 activity 的生命周期范围内收集流,该范围是主要安全的并且具有 activity 的生命周期意识。
并使我们的服务或存储库在不同的 CouroutineContext
中执行,使用中间运算符 flowOn
。
flowOn
更改上游流的 CoroutineContext
,这意味着生产者和在 flowOn
.
之前(或以上)应用的任何中间运算符
下游流(flowOn
之后的中间运算符和消费者)不受影响,并在用于从流中收集的 CoroutineContext
上执行。
视图模型:
fun getData():Flow<Data> = repository.observeData() // Execute on the io dispatcher
// flowOn affects the upstream flow ↑
.flowOn(Dispatchers.IO)
// the downstream flow ↓ is not affected
.catch { exception -> // Executes in the consumer's context
emit(Data())
}
Activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch { // Consumer's context
viewModel.getData().collect { // Suspended
textView.text = data.name // Collect on consumer's context
}
}
}
我有以下代码似乎阻塞了主线程,即使在 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)
}
}
}
ViewModel:
fun updateUI() {
scope.launch(Dispatchers.IO) {
repository.observerData().collect {
withContext(Dispatchers.Main) {
textView.text = data.name
}
}
}
}
根据 运行 下面的代码,我看到来自 Android Choreographer 的日志“跳过 200 帧。应用程序在主线程上工作太多”
要在数据流发出时使用 Kotlin Flows 收集数据流,请使用 collect
。而由于collect
是一个挂起函数,需要在协程中执行。它采用 lambda 作为参数,在每个新值上调用。由于它是一个挂起函数,调用 collect 的协程可能会挂起,直到流程关闭。
而且您不应该在 ViewModel 中更新 UI。
在这种情况下,我们在 activity 的生命周期范围内收集流,该范围是主要安全的并且具有 activity 的生命周期意识。
并使我们的服务或存储库在不同的 CouroutineContext
中执行,使用中间运算符 flowOn
。
flowOn
更改上游流的 CoroutineContext
,这意味着生产者和在 flowOn
.
下游流(flowOn
之后的中间运算符和消费者)不受影响,并在用于从流中收集的 CoroutineContext
上执行。
视图模型:
fun getData():Flow<Data> = repository.observeData() // Execute on the io dispatcher
// flowOn affects the upstream flow ↑
.flowOn(Dispatchers.IO)
// the downstream flow ↓ is not affected
.catch { exception -> // Executes in the consumer's context
emit(Data())
}
Activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch { // Consumer's context
viewModel.getData().collect { // Suspended
textView.text = data.name // Collect on consumer's context
}
}
}