第一次发出 kotlin 协程后,MutableStateFlow 不发出值

Rep*_*tor 14 kotlin kotlin-coroutines kotlin-coroutines-flow kotlin-coroutine-channel

这是我的 FirebaseOTPVerificationOperation 类,其中定义了我的 MutableStateFlow 属性,并更改了值,

    @ExperimentalCoroutinesApi
class FirebaseOTPVerificationOperation @Inject constructor(
    private val activity: Activity,
    val logger: Logger
) {
    private val _phoneAuthComplete = MutableStateFlow<PhoneAuthCredential?>(null)
    val phoneAuthComplete: StateFlow<PhoneAuthCredential?>
        get() = _phoneAuthComplete

    private val _phoneVerificationFailed = MutableStateFlow<String>("")
    val phoneVerificationFailed: StateFlow<String>
        get() = _phoneVerificationFailed

    private val _phoneCodeSent = MutableStateFlow<Boolean?>(null)
    val phoneCodeSent: StateFlow<Boolean?>
        get() = _phoneCodeSent

    private val _phoneVerificationSuccess = MutableStateFlow<Boolean?>(null)
    val phoneVerificationSuccess: StateFlow<Boolean?>
        get() = _phoneVerificationSuccess

    fun resendPhoneVerificationCode(phoneNumber: String) {
        _phoneVerificationFailed.value = "ERROR_RESEND"
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的视图模式,我在那里监听 stateflow 属性的变化,如下所示,

class OTPVerificationViewModal @AssistedInject constructor(
    private val coroutinesDispatcherProvider: AppCoroutineDispatchers,
    private val firebasePhoneVerificationListener: FirebaseOTPVerificationOperation,
    @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    @AssistedInject.Factory
    interface Factory {
        fun create(savedStateHandle: SavedStateHandle): OTPVerificationViewModal
    }

    val phoneAuthComplete = viewModelScope.launch {
        firebasePhoneVerificationListener.phoneAuthComplete.filter {
            Log.e("1","filter auth $it")
            it.isNotNull()
        }.collect {
            Log.e("2","complete auth $it")
        }
    }

    val phoneVerificationFailed = viewModelScope.launch {
        firebasePhoneVerificationListener.phoneVerificationFailed.filter {
            Log.e("3","filter failed $it")
            it.isNotEmpty()
        }.collect {
            Log.e("4","collect failed $it")
        }
    }

    val phoneCodeSent = viewModelScope.launch {
        firebasePhoneVerificationListener.phoneCodeSent.filter {
            Log.e("5","filter code $it")
            it.isNotNull()
        }.collect {
            Log.e("6","collect code $it")
        }
    }

    val phoneVerificationSuccess = viewModelScope.launch {
        firebasePhoneVerificationListener.phoneVerificationSuccess.filter {
            Log.e("7","filter success $it")
            it.isNotNull()
        }.collect {
            Log.e("8","collect success $it")
        }
    }

    init {
        resendVerificationCode()
        secondCall()
    }

    private fun secondCall() {
        viewModelScope.launch(coroutinesDispatcherProvider.io) {
            delay(10000)
            resendVerificationCode()
        }
    }

    fun resendVerificationCode() {
        viewModelScope.launch(coroutinesDispatcherProvider.io) {
            firebasePhoneVerificationListener.resendPhoneVerificationCode(
                getNumber()
            )
        }
    }

    private fun getNumber() =
            "+9191111116055"
}
Run Code Online (Sandbox Code Playgroud)

问题是 firebasePhoneVerificationListener.phoneVerificationFailed在第一次调用时在视图模式中触发, init { resendVerificationCode() }

但是对于 , 的第二次调用init { secondCall() } firebasePhoneVerificationListener.phoneVerificationFailed在 viewmodal 中没有被触发,我不知道为什么会发生这种情况,任何原因或解释都会非常有用。

电流输出: filter auth null filter failed filter code null filter success null filter failed ERROR_RESEND collect failed ERROR_RESEND

预期输出: filter auth null filter failed filter code null filter success null filter failed ERROR_RESEND collect failed ERROR_RESEND filter failed ERROR_RESEND collect failed ERROR_RESEND

Вла*_*нин 29

StateFlow 是 SharedFlow: https ://github.com/Kotlin/kotlinx.coroutines/issues/2034


我的文章中有更详细的描述:https://veldan1202.medium.com/kotlin-setup-sharedflow-31debf613b91


val shared = MutableSharedFlow(
    replay = 1,
    onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
shared.tryEmit(value)
Run Code Online (Sandbox Code Playgroud)

  • /sf/users/369540951/ - 当您可以连续发出相同的值时,需要 SharedFlow 而不是 StateFlow,因为 StateFlow 不会收集重复的元素。 (5认同)

小智 9

状态流发出的值被混合并且不会两次发出相同的连续结果,您可以认为好像条件检查正在验证旧的发出值不等于新发出的值。

当前输出:filter auth null filter failed filter code null filter success null filter failed ERROR_RESEND collect failed ERROR_RESEND

(过滤器失败 ERROR_RESEND 收集失败 ERROR_RESEND)这是与发出的旧值相同的值,因此您不会看到它们被发出。


vik*_*mar 8

使用 a Channel:这会在两次发送相同的值后发出。

  1. 将此添加到您的 ViewModel

    val _intent = Channel(Channel.CONFLATED)

  2. 使用send/放置值trySend

    _intent.send(intentLocal)

  3. 观察流动

    _intent.consumeAsFlow().collect { // 做某事 }

  • `Channel` 比 `MutableStateFlow` 更好? (4认同)
  • `MutableStateFlow` 本质上是合并的,所以你应该使用 `Channel.CONFLATED` 来模仿它的行为 (2认同)
  • @deviant Channel 并未被弃用,你从哪里得到的? (2认同)

Sir*_*lot 7

Pankaj 的答案是正确的,StateFlow不会两次发出相同的值。正如文档所暗示的那样:

状态流中的值以Any.equalsdistinctUntilChanged运算符类似的方式使用比较进行合并。它用于将传入的更新合并到valueinMutableStateFlow并在新值等于先前发出的值时抑制将值发射到收集器。

因此,要解决此问题,您可以创建一个包装类并覆盖equals(and hashCode) 方法以返回,false即使这些类实际上是相同的:

sealed class VerificationError {
    object Resend: VerificationError()

    override fun equals(other: Any?): Boolean {
        return false
    }

    override fun hashCode(): Int {
        return Random.nextInt()
    }
}
Run Code Online (Sandbox Code Playgroud)