我需要在MVVM中获取用户身份验证状态.在存储库中,我执行以下操作:

override fun getAuthResponse() = callbackFlow  {
    val listener = AuthStateListener {
        Log.d(TAG, "currentUser: " + (currentUser == null)) //Line2
        trySend(it.currentUser == null)
    }
    auth.addAuthStateListener(listener)
    awaitClose {
        auth.removeAuthStateListener(listener)
    }
}

"Line2"将始终打印true,因为用户未经过身份验证.然后,在ViewModel中,我拥有:

fun getAuthResponse() = repo.getAuthResponse()

和内部活动:

setContent {
    //...
    val response = viewModel.getAuthResponse().collectAsState(initial = false).value
    Log.d(TAG, "response: $response") //Line1
}

因为setContent是一个可组合的函数,所以当我打开应用程序时,它会触发两次.这意味着"Line1"处的LOG语句被触发两次.当它第一次开火时,我会得到:

response: false
currentUser: true

因此,即使我在前一行调用了getAuthResponse(),响应也是在前面打印的.问题是,出于某种原因,即使当前用户为空,我也会在活动中得到该用户不为空的消息.当它第二次emits 时,我得到了正确的数据:

response: true
currentUser: true

为什么我会得到一个非空的用户对象?try 发送是否会发出虚假数据?

推荐答案

这里的问题是,流在设计上是异步的.即使您希望AuthStateListener在注册后立即被调用,流最初仍然没有任何值.collectAsState()需要一个值,它不能只为空,因此它需要您提供一个初始值.你提供了false,这是你最初得到的response.然后几乎立即调用侦听器,它发出true,然后response也变为true.

我们有多种方法可以解决这类问题.例如,我们最初可以显示一个加载屏幕,直到我们获得正确的值.在上面的例子中,我们可以直接获得currentUser的值,而不需要使用侦听器,所以我建议使用StateFlow.StateFlow不同于常规的Flow,因为它能够保持其"当前"值.最简单的方法是使用MutableStateFlow:

override fun getAuthResponse(): StateFlow<Boolean> {
    val flow = MutableStateFlow(auth.currentUser == null)

    val listener = AuthStateListener {
        Log.d(TAG, "currentUser: " + (currentUser == null)) //Line2
        flow.value = it.currentUser == null
    }
    auth.addAuthStateListener(listener)

    return flow
}

setContent {
    //...
    val response = viewModel.getAuthResponse().collectAsState().value
    Log.d(TAG, "response: $response") //Line1
}

这个解决方案可能不是100%正确的,因为我不能测试它,但我希望你能理解.

Kotlin相关问答推荐

如何在Jetpack Compose中从领域查询中读取数据?

Kotlin中函数引用的否定

如何接受任何派生类KClass

为什么 Kotlin main 函数需要 @JVMStatic 注解?

可组合项在返回后返回时组合导航句柄

修改器的属性是什么,我需要更改以使角变圆且宽度更小?喷气背包组合

在 Kotlin 中 import 如何找到文件路径?

如何在 Kotlin 中将with代码转换为完整代码?

Jetpack Compose - 单击 LazyColumn 的项目时应用程序崩溃

禁用 Android 12 默认启动画面

从 Java 调用 Kotlin 高阶函数

Kotlin 中的数据类

使用 clear() 删除 EncryptedSharedPreferences 不起作用

Mockito 的 argThat 在 Kotlin 中返回 null

Android 与 Kotlin - 如何使用 HttpUrlConnection

如何让数据类在Kotlin中实现接口/扩展超类属性?

在Kotlin中将列表转换为对的惯用方法

Kotlin flatMap - map

在多平台子元素中使用kapt

RxJava2 UndeliverableException 在获取数据时发生方向变化