gpt4 book ai didi

android - 从 viewModelScope 中的 Flow 收集数据是否会阻止 Android Studio 中的 UI?

转载 作者:行者123 更新时间:2023-12-04 23:55:40 25 4
gpt4 key购买 nike

代码A来自官方article关于流量viewModelScope.launch{}默认在 UI 线程中运行,我认为 suspend fun fetchLatestNews()默认情况下也会在 UI 线程中运行,所以我认为代码 A 可能会在 fetchLatestNews() 时导致 UI 阻塞是长时间的操作吧?
我认为代码 B 可以解决问题,对吧?
代码 A

class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {

init {
viewModelScope.launch {
// Trigger the flow and consume its elements using collect
newsRepository.favoriteLatestNews.collect { favoriteNews ->
// Update View with the latest favorite news
}
}
}
}



class NewsRemoteDataSource(
private val newsApi: NewsApi,
private val refreshIntervalMs: Long = 5000
) {
val latestNews: Flow<List<ArticleHeadline>> = flow {
while(true) {
val latestNews = newsApi.fetchLatestNews()
emit(latestNews) // Emits the result of the request to the flow
delay(refreshIntervalMs) // Suspends the coroutine for some time
}
}
}

// Interface that provides a way to make network requests with suspend functions
interface NewsApi {
suspend fun fetchLatestNews(): List<ArticleHeadline>
}
代码 B
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {

init {
viewModelScope.launch(Dispatchers.IO) {
//The same
}
}
}


//The same
新增内容:
致 Tenfour04:谢谢!
我认为挂起功能可能会阻塞 UI,所以我想定义 dispatchers为了不阻塞UI,最重要的是!这样对吗?
如果我使用 Dispatchers.IO,当我单击“开始”按钮显示信息时,代码 1 运行良好.
如果我使用 Dispatchers.Main,当我单击“开始”按钮时,代码 2 被卡住并且没有信息更新.
如果我使用 Dispatchers.Main,代码 3 可以像代码 1 一样工作,原因只是因为我设置了 delay(100) .
顺便说一句,Flow 已暂停。所以如果有很长时间的操作,即使它是用协程而不是 soundDbFlow().collect { myInfo.value = it.toString() } 包装的, 我想我可以得到和 Code 1, Code 2 和 Code 3 一样的测试结果。
更重要的是,在我添加 flowOn(Dispatchers.IO) 后,代码 4 就可以了对于 Flow,即使它是在 viewModelScope.launch(Dispatchers.Main){} 中启动的!
代码 1 确定
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("World")
private var myJob: Job?=null
private var k=0

private fun soundDbFlow() = flow {
while (true) {
emit(k++)
delay(0)
}
}

fun calCurrentAsynNew() {
myJob?.cancel()
myJob = viewModelScope.launch(Dispatchers.IO){
soundDbFlow().collect { myInfo.value = it.toString() }
}
}

fun cancelJob(){
myJob?.cancel()
}

}


@Composable
fun Greeting(handleMeter: HandleMeter) {
var info = handleMeter.myInfo
Column(
modifier = Modifier.fillMaxSize()
) {
Text(text = "Hello ${info.value}")

Button(
onClick = { handleMeter.calCurrentAsynNew() }
) {
Text("Start")
}

Button(
onClick = { handleMeter.cancelJob() }
) {
Text("Stop")
}
}
}
代码 2 卡住
class HandleMeter: ViewModel() {
private fun soundDbFlow() = flow {
while (true) {
emit(k++)
delay(0)
}
}

fun calCurrentAsynNew() {
myJob?.cancel()
myJob = viewModelScope.launch(Dispatchers.Main){
soundDbFlow().collect { myInfo.value = it.toString() }
}
}
...
//The same

}
...
//The same
代码 3 确定
class HandleMeter: ViewModel() {
private fun soundDbFlow() = flow {
while (true) {
emit(k++)
delay(100) //It's 100
}
}

fun calCurrentAsynNew() {
myJob?.cancel()
myJob = viewModelScope.launch(Dispatchers.Main){
soundDbFlow().collect { myInfo.value = it.toString() }
}
}
...
//The same

}
...
//The same
代码 4 确定
class HandleMeter: ViewModel() {
private fun soundDbFlow() = flow {
while (true) {
emit(k++)
delay(0)
}
}.flowOn(Dispatchers.IO)// I added

fun calCurrentAsynNew() {
myJob?.cancel()
myJob = viewModelScope.launch(Dispatchers.Main){
soundDbFlow().collect { myInfo.value = it.toString() }
}
}

...
//The same

}
...
//The same

最佳答案

挂起函数不会阻塞,除非它违反了挂起函数永远不能阻塞的约定。因此,从主调度程序调用您的协程并不重要。调用fetchLatestNews()不会阻塞主线程, 除非你不正确地组合了函数的实现,以至于它实际上阻塞了。
您通常不需要像在 中那样执行此操作。代码 B :

viewModelScope.launch(Dispatchers.IO) {
因为您通常不会在协程的顶层调用阻塞函数。如果你是,你可以用 withContext(Dispatchers.IO) { } 包裹这些 fragment .将协程留在 Main 调度程序上通常更方便,因为 Android 中有很多非挂起函数需要您从主线程调用它们。如果你翻转它,你可能需要 withContext(Dispatchers.Main) { }在比你需要的地方更多的地方,你也会在协程实际开始之前产生一帧延迟。此外,如果您的协程与 ViewModel 中的属性交互,如果您只从 Main 调度程序中触摸它们,您可以避免并发访问属性的潜在问题,因为它是单线程的。
可能存在一些异常(exception)情况,即您启动的协程不与任何此类 Main 必需的函数交互并直接调用阻塞函数,但我认为这应该很少见,特别是如果您练习良好的封装 ( see here)。如果你将协程顶层的一段代码分解成它自己的函数,你可以把那个单独的函数变成一个使用 withContext(Dispatchers.IO) 的挂起函数。如有必要。然后你的顶级协程会看起来很干净。

关于android - 从 viewModelScope 中的 Flow 收集数据是否会阻止 Android Studio 中的 UI?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70891060/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com