提问人:heet kanabar 提问时间:6/20/2023 最后编辑:heet kanabar 更新时间:6/29/2023 访问量:361
'awaitClose { yourCallbackOrListener.cancel() }' 应在 callbackFlow 块的末尾使用。Kotlin 流程中的错误
'awaitClose { yourCallbackOrListener.cancel() }' should be used in the end of callbackFlow block. Error in Kotlin flow
问:
我有一个应用程序,用户可以上传他们的壁纸并下载它,并且可以看到它,所以当用户登录并为了从 firestore 获取用户的详细信息时,我有这个功能,我将获取用户的详细信息:-
override suspend fun getUserDetails(userId: String): Flow<Response<User>> = callbackFlow {
val listener = fireStore.collection(Consts.USERS_COLLECTION_NAME)
.document(userId)
.addSnapshotListener { snapShot, error ->
val result = if (snapShot != null) {
val userInfo = snapShot.toObject(User::class.java)
Response.Success(userInfo!!)
} else {
Response.Error(error?.message ?: error.toString())
}
trySend(result)
}
// awaitClose()
awaitClose {
this.cancel()
listener.remove()
close()
}
}
我收到这个错误:-
java.lang.IllegalStateException: 'awaitClose { yourCallbackOrListener.cancel() }' 应该在 callbackFlow 块。
我看到了很多关于它的问题,我尝试过聊天 gpt 的代码,但一次又一次地遇到同样的错误。
我的观点模型:-
viewModelScope.launch {
if (!firebaseUser?.isAnonymous!!){
userRepo.getUserDetails(firebaseUser.uid).collect{
when(it){
is Response.Error -> sendUIEvents(UIEvents.ShowSnackBar(it.message))
is Response.Loading -> Unit
is Response.Success -> {
// Some code
}
}
}
}
}
我的用户流程是这样的:-
初始屏幕 > 主屏幕 > 个人资料屏幕 > 上传壁纸屏幕
注意:-上面的代码位于主屏幕和配置文件屏幕中,我在主屏幕中收到此错误。
如果您有任何可能的答案,那么您可以发布它,还有一件事,我在不同的文件中有非常精确的代码,甚至没有更改变量名称,并且我没有收到任何错误,我只从此代码中收到错误。谢谢。
我的全栈:-
FATAL EXCEPTION: main Process: com.example.wallz, PID: 709 java.lang.IllegalStateException: 'awaitClose { yourCallbackOrListener.cancel() }' should be used in the end of callbackFlow block. Otherwise, a callback/listener may leak in case of external cancellation. See callbackFlow API documentation for the details. at kotlinx.coroutines.flow.CallbackFlowBuilder.collectTo(Builders.kt:343) at kotlinx.coroutines.flow.internal.ChannelFlow$collectToFun$1.invokeSuspend(ChannelFlow.kt:60) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:69) at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:245) at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:161) at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397) at kotlinx.coroutines.CancellableContinuationImpl.completeResume(CancellableContinuationImpl.kt:513) at kotlinx.coroutines.channels.AbstractChannel$ReceiveElement.completeResumeReceive(AbstractChannel.kt:908) at kotlinx.coroutines.channels.ArrayChannel.offerInternal(ArrayChannel.kt:83) at kotlinx.coroutines.channels.AbstractSendChannel.trySend-JP2dKIU(AbstractChannel.kt:155) at kotlinx.coroutines.channels.ChannelCoroutine.trySend-JP2dKIU(Unknown Source:2) at com.example.wallz.data.repositories.UserRepoImpl$getUserDetails$2.invokeSuspend$lambda-0(UserRepoImpl.kt:109) at com.example.wallz.data.repositories.UserRepoImpl$getUserDetails$2.$r8$lambda$BnGWgnacAYeEFR-hHCZ0JzY-fc0(Unknown Source:0) at com.example.wallz.data.repositories.UserRepoImpl$getUserDetails$2$$ExternalSyntheticLambda0.onEvent(Unknown Source:4) at com.google.firebase.firestore.DocumentReference.lambda$addSnapshotListenerInternal$2$com-google-firebase-firestore-DocumentReference(DocumentReference.java:504) at com.google.firebase.firestore.DocumentReference$$ExternalSyntheticLambda2.onEvent(Unknown Source:6) at com.google.firebase.firestore.core.AsyncEventListener.lambda$onEvent$0$com-google-firebase-firestore-core-AsyncEventListener(AsyncEventListener.java:42) at com.google.firebase.firestore.core.AsyncEventListener$$ExternalSyntheticLambda0.run(Unknown Source:6) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8751) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135) Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@b3d76f0, Dispatchers.Main.immediate]
答:
您不得从内部致电或从内部致电。当您的 lambda in 被调用时,协程已经取消或通道关闭,因此它是多余的。cancel()
close()
awaitClose
awaitClose
callbackFlow
旨在在调用失败时抛出此异常,但它们检测到未调用它的方式也是由意外调用冗余或 触发的。因此,不幸的是,它不会在异常中为您提供有用的错误消息。awaitClose
cancel()
close()
评论
.flowOn(Dispatchers.Main)
首先,有几件事:
- 由于您返回的是流,因此不需要将函数设为函数。
suspend
- 您不需要在块中使用 和。
cancel()
close()
awaitClose {}
要修复此错误,请确保您使用的是正确的导入:
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
评论
这是我的解决方案,也是我经过长期研究后发现的:-
override suspend fun getUserDetails(userId: String): Flow<Response<User>> = callbackFlow {
try {
val snapshot = fireStore.collection(Consts.USERS_COLLECTION_NAME)
.document(userId)
.get()
.await()
val user = snapshot.toObject(User::class.java)
val result = if (user != null) {
Response.Success(user)
} else {
Response.Error("Could not get user's data.")
}
trySend(result)
close()
awaitCancellation()
} catch (e: Exception) {
trySend(Response.Error(e.message ?: e.toString()))
}
}.flowOn(Dispatchers.IO)
这是从firebase获取数据的正确方法,这不会产生任何错误和任何异常。
在这里,我在代码中使用了函数和函数,最后我使用了函数。get()
await()
awaitCancellation()
评论
catch
close()
awaitCancellation()
callbackFlow
callbackFlow
flow
评论