You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin callbackFlow中awaitClose位置错误引发IllegalStateException问题

问题排查与解决方案

问题分析

  1. 核心报错原因:callbackFlow的实现违反了框架规范——在awaitClose块内手动调用this.cancel()和close()会干扰内部通道的生命周期管理,触发框架的合法性检查,导致抛出IllegalStateException。即使awaitClose写在代码最后,内部错误操作也会让框架判定其未正确执行收尾逻辑。
  2. 仅首页报错的诱因:首页的协程收集未与页面生命周期绑定,页面销毁时收集操作未及时取消,触发了Firestore监听器泄漏的检查逻辑;而其他页面的生命周期管理更严谨(如使用了生命周期感知的收集方式),因此未触发报错。

解决方案

1. 修复getUserDetails的callbackFlow实现

正确的callbackFlow只需在awaitClose中清理Firestore监听器,无需手动操作通道的cancel或close:

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)
                // 替换!!为安全处理,避免空指针
                userInfo?.let { Response.Success(it) } ?: Response.Error("User data is null")
            } else {
                Response.Error(error?.message ?: "Unknown error occurred")
            }
            trySend(result)
        }

    // 仅在Flow被取消时移除监听器,无需额外操作通道
    awaitClose {
        listener.remove()
    }
}

2. 优化ViewModel的收集逻辑

确保收集操作与页面生命周期绑定,避免协程和监听器泄漏:

  • Jetpack Compose场景(Home Screen的Composable内):
LaunchedEffect(Unit) {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        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 -> {
                        // 处理用户信息逻辑
                    }
                }
            }
        }
    }
}
  • 传统View系统场景(Home Fragment/Activity内):
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.run {
            if (!firebaseUser?.isAnonymous!!){
                userRepo.getUserDetails(firebaseUser.uid).collect{
                    // 处理逻辑
                }
            }
        }
    }
}

额外优化点

  • 移除代码中被注释的// awaitClose()行,避免编译或静态检查的潜在干扰;
  • 替换userInfo!!为安全空值处理,避免Firestore返回空对象时触发空指针异常。

内容的提问来源于stack exchange,提问作者heet kanabar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:13:17