假设在VM内使用viewModelScope
启动了一个新协程,并在通用存储库类内调用了一个非暂停函数
UserViewModel
viewModelScope.launch(context = Dispatchers.IO) {
_user.value?.id?.let { id ->
val dataSaved = userRepository.setUserData(id, newUser)
}
}
UserRepository
fun setUserData(id: String, data: User): Boolean {
return try {
val saveTask = db.collection(COLLECTION).document(id).set(data)
Tasks.await(saveTask)
true
} catch (e: Throwable) {
false
}
}
setUserData
的范围和上下文是什么?suspend
函数之前添加了setUserData
键盘,则await
的{{1}}方法将生成警告Tasks
。为什么?Inappropriate blocking method call
suspend fun setUserData(id: String, data: User): Boolean {
return coroutineScope {
return@coroutineScope try {
val saveTask = db.collection(COLLECTION).document(id).set(data)
Tasks.await(saveTask)
true
} catch (e: Throwable) {
e.printStackTrace()
Log.e(TAG, "${e.message}")
false
}
}
}
是否可以保证在呼叫者的相同范围和上下文中启动coroutineScope
?答案 0 :(得分:0)
启动
setUserData
的范围和上下文是什么?
从viewModelScope.launch(context = Dispatchers.IO)
来看,上下文看起来像CoroutineScope(SupervisorJob() + Dispatchers.IO)
。
如果我在
suspend
函数之前添加了setUserData
键盘,则await
的{{1}}方法将生成警告Tasks
。为什么?
除非在调度程序中支持,否则在挂起函数中阻塞线程(使用Inappropriate blocking method call
)是不好的做法。即Tasks.await
。
IntelliJ / Android Studio不够聪明(而且可能不够聪明),无法准确确定您是否在不应该这样做的时候进行阻止。因此,这可以被认为是一个错误,但是可以在Dispatchers.IO
之外调用setUserData
,因此IntelliJ有一个要点。
此实现有什么区别?
真的不多。只是有一些额外的开销是不值得的。
作为旁注,Dispatchers.IO
不会像coroutineScope
那样更改直接coroutineContext
,但会更改已启动协程的继承上下文。
withContext
是否可以保证在呼叫者的相同范围和上下文中启动coroutineScope
?
您已经获得此保证。您不需要setUserData
即可实现。
您可能想要的是这个。
coroutineScope
然后,调用方不必担心要使用哪个调度程序或上下文。
您应该使用的是这个。
suspend fun setUserData(id: String, data: User): Boolean {
val saveTask = db.collection(COLLECTION).document(id).set(data)
return withContext(Dispatchers.IO) {
try {
Tasks.await(saveTask)
true
} catch (e: Throwable) {
e.printStackTrace()
Log.e(TAG, "${e.message}")
false
}
}
}
通过这种方式,您无需唤醒suspend fun setUserData(id: String, data: User): Boolean {
val saveTask = db.collection(COLLECTION).document(id).set(data)
return try {
saveTask.await() // From `kotlinx-coroutines-play-services`
true
} catch (e: Throwable) {
e.printStackTrace()
Log.e(TAG, "${e.message}")
false
}
}
并阻止更多线程。