我有六个函数,总的来说,我将分三步执行它们。
首先,变量userPointArray
将用于如下所示。
var userPointArray = ArrayList<UserPoint>()
data class UserPoint(
var userId: String,
var point: Int,
var index: Int
)
我的三个步骤将在下面。
1.从firebase获取userId
数据并将其放入userPointArray -〉一个函数
1.从firebase获取四个数据,计算point
字段-〉四个函数
1.根据点更新index
-〉一个函数
由于我需要以三个步骤的顺序执行总共6个函数,因此我将使用Coroutine
。
步骤1功能
suspend fun userIdToArrayFun() = withContext(Dispatchers.IO) {
userDB.get()
.addOnSuccessListener { documents ->
for (document in documents) {
var userId = document.data?.getValue("userId").toString()
var userEntry = UserPoint(
userId,
0,
0
)
userPointArray.add(userEntry)
dataToUserPointArray.userIdToArray.value = true
}
}
true
}
步骤2功能
:此步骤中的四个函数是stepCountToArrayFun()、diaryArrayFun()...
suspend fun calculatePointFun() = withContext(Dispatchers.IO) {
try {
listOf(
launch { stepCountToArrayFun() },
launch { diaryToArrayFun() },
launch { commentToArrayFun() },
launch { likeToArrayFun() }
).joinAll()
false
} catch (e: Throwable) {
true
}
}
步骤3功能
fun indexArrayFun() = with(Dispatchers.IO) {
userPointArray.sortWith(compareBy { it.point })
var initialindex: Int = 1
for (i in userPointArray.indices) {
userPointArray[i].point = initialindex
if (userPointArray[i + 1].point != userPointArray[i].point) {
initialindex++
}
}
true
}
最后,我执行这些顺序步骤1 -〉步骤2-〉步骤3如下:
var fullUserArrayPointFun = CoroutineScope(Dispatchers.Default).launch {
if (userIdToArrayFun()) {
calculatePointFun()
}
if(calculatePointFun()) {
indexArrayFun()
}
}
因为我是新的协程,我只是写代码作为搜索,我想我的代码是奇怪的,特别是我的最后一个代码,执行这三个步骤的代码顺序。
你能回顾每三个步骤的代码和我的最后一个代码吗?
1条答案
按热度按时间z31licg01#
我建议阅读RomanElizarov在Medium上的文档和博客文章,以便在尝试使用它们之前牢牢掌握基本的协程概念。
下面是您发布的代码的简要回顾:
步骤1函数
用suspend函数调用异步函数是没有意义的,你的suspend函数是不会等它的,你可以用
suspendCancellableCoroutine
把异步函数转换成suspend函数,但是Firebase不需要,因为它已经为您提供了一个suspend函数,您应该使用await()
suspend函数,而不是添加异步侦听器。它应该看起来像这样,但是我可能有点偏离,因为我没有使用Firebase,我真的不知道你在for循环中做了什么:步骤2功能
如果你正在调用的四个函数是 blocking 函数,那么你当前的代码是正确的;如果它们是suspend函数或非blocking函数,那么切换上下文是没有意义的,可以使用
coroutineScope {
而不是withContext(Dispatchers.IO) {
来使代码清晰。如果这四个函数都是等待结果的suspend函数,那么我对步骤1的评论也适用于您如何实现它们。
步骤3功能
你对
with(Dispatchers.IO)
的使用使IO
成为lambda的接收者--它是with
作用域函数,我想你把它和withContext
弄混了。如果这段代码不使用一个巨大的数组,它就不会阻塞,所以你可以删除
with
Package 器,让它保持原样。但是如果它的数据量足够大,需要花费一定的时间,你可以将它改为一个挂起函数,并使用withContext(Dispatchers.Default)
来卸载协同程序上任何线程的工作。我建议使用Default而不是IO,因为它不是IO绑定的。最后一步
你不应该创建一个
CoroutineScope()
而不把它存储在一个属性中,这样你就可以管理它的生命周期。如果你真的不需要管理它的生命周期,你可以使用GlobalScope,但是你不关心一个协程的生命周期是非常罕见的。它使用资源,所以当它相关的任何UI过时时,您希望取消协程,这样资源就不会浪费(内存泄漏和/或不必要的CPU/网络/磁盘使用)。在Android上,绝大多数协程应该从
lifecycleScope
或viewModelScope
启动,因为这些协程作用域已经为您提供,并且在其关联的UI被销毁时会自动取消。另外,你调用了你的
calculatePointFun()
两次,这是没有意义的。我会像下面这样写你的代码。你不需要把你的协程的Job赋给一个变量,除非你有一些情况下,你需要提前取消它。您正在使用
userIdToArrayFun()
,就好像它返回布尔值一样。您是否希望它在失败时返回false
,在成功时返回true?