我使用的是Firebase身份验证。在存储库中,我使用了以下函数:
override suspend fun signIn(): Result<Boolean> {
return try {
auth.signInAnonymously().await()
Result.Success(true)
} catch (ex: Exception) {
Result.Failure(ex)
}
}
此函数从ViewModel类中调用:
var response by mutableStateOf<Result<Boolean>>(Result.Success(false))
private set
fun signIn() = viewModelScope.launch {
response = repository.signIn()
}
它工作正常,但我被建议在ViewModel中使用:
fun signIn() = viewModelScope.launch(Dispatchers.IO) {
response = repository.signIn()
}
要在存储库中添加Dispatchers.IO
和:
override suspend fun signIn(): Result<Boolean> {
return withContext(Dispatchers.IO) {
try {
auth.signInAnonymously().await()
Result.Success(true)
} catch (ex: Exception) {
Result.Failure(ex)
}
}
}
用withContext
启动一个协程。我不明白为什么?我用的是Jetpack编写。
3条答案
按热度按时间xfyts7mz1#
不管是谁建议修改你的代码都是错的。
一般的Kotlin协程约定是,挂起函数永远不需要在特定的调度器上被调用,特别是因为它们永远不能阻塞。如果需要,它们总是在内部委托给特定的调度器。(但也许作为一种优化,一个 private suspend函数可以避免为必须在主调度器上被调用的函数这样做。)
由于这是一个约定,来自Google、Android、Square等的所有库以及任何知道自己在做什么的人,都只有
suspend
函数可以从 * 任何 * 调度器调用。这包括你在Firebase中使用的
await()
调用,因此,你的仓库的signIn
函数已经非常好了,因为它不调用任何阻塞函数,并且它调用的suspend函数是一个正确的suspend函数,也不阻塞,所以它符合标准(它不阻塞)。ViewModel中的函数也很好,不需要指定调度程序。
yqkkidmi2#
实际上,由于您已经从以
Dispatchers.IO
开头的协程调用signIn
,因此不必使用return withContext(...)
。因为您的存储库方法是
suspend
,所以它能够调用协程,而不需要像withContext
这样的特殊块。在存储库中,您可以
fae0ux8s3#
我们有两种方法来启动协同异步和启动。
1.launch将用于在后台执行串行/序列任务。
1.async在我们期望返回一些结果并且还希望执行并行操作时使用。
同样的方式withContext只是编写异步的另一种方式,在这种方式下,用户不必编写await()。当使用withContext时,它会串行而不是并行地运行任务。因此,用户应该记住,当我们在后台有一个任务,并且想要返回该任务的结果时,我们应该使用withContext。
在您的情况下,可以按如下所示更改代码
并删除with上下文
如果您不想将return与withContext一起使用,还有一种方法
简单地说,如果你希望任务有结果,那么你必须使用async或者withContext。
希望我能解决你的问题或问题。