Kotlin 如何等待流完成发送值
我的存储库中有一个函数“getUser”,它根据提供的id发出一个表示用户的对象 我需要在另一个类中使用这些值。我在ID列表上循环,并将收集的用户添加到新列表中。在调用return之前,如何在收集值时等待列表完成Kotlin 如何等待流完成发送值,kotlin,Kotlin,我的存储库中有一个函数“getUser”,它根据提供的id发出一个表示用户的对象 我需要在另一个类中使用这些值。我在ID列表上循环,并将收集的用户添加到新列表中。在调用return之前,如何在收集值时等待列表完成 private fun ComputeAttendesList(提醒:提醒):ArrayList{ val AttendesList=arrayListOf() for(提醒中的朋友。usersToShare){ repoScope.launch{ Repository.getUs
private fun ComputeAttendesList(提醒:提醒):ArrayList{
val AttendesList=arrayListOf()
for(提醒中的朋友。usersToShare){
repoScope.launch{
Repository.getUser(friend.collect){
它?让{user->
如果(!AttendesList.contains(用户))
AttendesList.add(用户)
}
}
}
}
返回与会者列表
}
我不想使用实时数据,因为这不是与UI相关的类。此代码中有多个问题需要解决:
getUser()
用于返回单个用户
,但它当前返回一个流
它永远不会结束,也不会返回多个用户launch
e在多线程IO dispatcher上执行,并且它们都直接更新相同的不安全列表)getUser()
,它为单个用户
挂起,而不是返回流
:
suspend fun getUser(id:String):用户{
val collectionReference=FirebaseFirestore.getInstance().collection(集合用户)
val query=collectionReference.whereEqualTo(ID,ID)
return query.get().await().let{it.toObjects(User::class.java)}.firstOrNull()
}
//请改用kotlinx协同程序播放服务库
私有挂起有趣的任务。等待():T{
返回SuspendCancelableCoroutine{cont->
addOnCompleteListener{
val e=异常
如果(e==null){
@抑制(“未选中的_CAST”)
如果(已取消)继续取消()否则继续恢复(结果为T)
}否则{
续:除例外情况外的简历(e)
}
}
}
}
事实证明,这个await()
函数已经编写好了(以更好的方式),并且在中可用,因此您不需要亲自编写它
#2的解决方案
如果我们不能按照#3重写整个过程,我们可以通过以下方式处理问题#2:
private suspend fun computeAttendeesList(提醒:提醒):列表{
返回提醒。usersToShare
.map{friendId->
repoScope.async{Repository.getUser(friendId)}
}
.map{it.await()}
托利斯先生()
}
#3的解决方案
相反,我们可以直接向Firebase查询整个列表:
suspend-fun-getUsers(id:List):List{
val collectionReference=FirebaseFirestore.getInstance().collection(集合用户)
val query=collectionReference。其中(ID,ID)
return query.get().await().let{it.toObjects(User::class.java)}
}
然后以一种非常基本的方式消费它:
private suspend fun computeAttendeesList(提醒:提醒):列表{
return Repository.getUsers(remention.usersToShare)
}
或者,您可以使此函数阻塞(removesuspend
),并将调用包装到runBlocking
(如果您确实需要阻塞当前线程)
请注意,此解决方案没有强制执行任何调度程序,因此如果您需要特定的作用域或调度程序,可以使用
withContext
包装其中一个挂起函数调用。请不要发布屏幕截图,它们不可搜索,并且很难生成有用的响应,因为我们需要键入所有内容。请在您的问题中使用代码块粘贴代码。您希望您的ComputeAttendesList
在等待时做什么?你想让它暂停吗?还是阻止当前线程?如果是前者,您应该使方法本身挂起
,如果是后者,您可以使用运行阻塞
。在任何一种情况下,您都有多种方法来实现这一点,因此这将有助于获得更多关于您希望在哪个范围内运行东西,以及您希望阻止哪些线程(如果有)的信息。抱歉@Joffrey,我发布了代码。好的,我需要是一个阻塞代码,只有在计算了AttendesList
之后,我才希望被返回以供另一个函数使用。另外,您的repoScope
是单线程的吗?因为您同时更新的ArrayList在这里不是线程安全的。如果您希望它提供一个完成的列表,那么使用一个suspend fun getList():list
并从挂起上下文调用它。我认为你试图用一种解决方案解决两个问题。流很好地发出了构建列表所需的值,但是如果您需要一个完成的列表,感兴趣的对象应该只接收这样的内容。是的,谢谢,#3是最好的方法,我刚刚更改了它,它可以工作。祝您有个美好的一天!
fun getUser(id: String) = callbackFlow {
val collectionReference: CollectionReference =
FirebaseFirestore.getInstance().collection(COLLECTION_USERS)
val query: Query = collectionReference.whereEqualTo(ID, id)
query.get().addOnSuccessListener {
val lst = it.toObjects(User::class.java)
if (lst.isEmpty())
offer(null)
else
offer(it.toObjects(User::class.java)[0])
}
awaitClose()
}
private fun computeAttendeesList(reminder: Reminder): ArrayList<User> {
val attendeesList = arrayListOf<User>()
for (friend in reminder.usersToShare) {
repoScope.launch {
Repository.getUser(friend).collect {
it?.let { user ->
if (!attendeesList.contains(user))
attendeesList.add(user)
}
}
}
}
return attendeesList
}