Hel*_*oCW 5 android kotlin kotlin-coroutines
代码A来自Flow的官方文章
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>
}
Run Code Online (Sandbox Code Playgroud)
代码B
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
init {
viewModelScope.launch(Dispatchers.IO) {
//The same
}
}
}
//The same
Run Code Online (Sandbox Code Playgroud)
新增内容:
致 Tenfour04: 谢谢!
我认为挂起函数可能会阻塞UI,所以我认为定义dispatchers是最重要的,以免阻塞UI!这样对吗?
当我单击“开始”按钮显示信息(如果我使用Dispatchers.IO.
如果我使用Dispatchers.Main.
如果我使用代码3,它可以像代码1一样工作Dispatchers.Main,原因只是因为我设置了delay(100)。
顺便说一句,流程已暂停。因此,如果有一个很长时间的操作,即使它是用协程而不是包装起来的soundDbFlow().collect { myInfo.value = it.toString() },我想我也可以得到与代码1、代码2和代码3相同的测试结果。
而且,在我flowOn(Dispatchers.IO)为流程添加后,代码 4 就可以了,即使它是在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")
}
}
}
Run Code Online (Sandbox Code Playgroud)
代码 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
Run Code Online (Sandbox Code Playgroud)
代码 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
Run Code Online (Sandbox Code Playgroud)
代码 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
Run Code Online (Sandbox Code Playgroud)
挂起函数不会阻塞,除非它打破了挂起函数绝不能阻塞的约定。因此,从主调度程序调用您的协程并不重要。主线程不会因调用而被阻塞fetchLatestNews(),除非您不正确地编写了函数的实现,导致它实际上被阻塞。
您通常不需要像代码 B中那样执行此操作:
viewModelScope.launch(Dispatchers.IO) {
Run Code Online (Sandbox Code Playgroud)
因为您通常不会在协程的顶层调用阻塞函数。如果是的话,您可以将这些碎片包裹在withContext(Dispatchers.IO) { }. 通常,将协程留在主调度程序上会更方便,因为 Android 中有很多非挂起函数需要从主线程调用它们。如果你翻转它,你可能需要withContext(Dispatchers.Main) { }比反转更多的地方,并且在协程实际启动之前还会产生一帧延迟。此外,如果您的协程与 ViewModel 中的属性进行交互,则如果您仅从主调度程序中接触这些属性,则可以避免并发访问这些属性时出现的潜在问题,因为它是单线程的。
可能存在例外情况,即您启动的协程不与任何此类 Main 所需的函数交互并且直接调用阻塞函数,但我认为这种情况应该很少见,特别是如果您练习良好的封装(请参阅此处)。如果将协程顶层的一段代码分解为自己的函数,则可以将该单独的函数放入一个挂起函数中,以便withContext(Dispatchers.IO)在必要时使用。那么你的顶级协程就会看起来非常干净。
| 归档时间: |
|
| 查看次数: |
2925 次 |
| 最近记录: |