这是我的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"
}
}
这是我的视图模态,从那里我听状态流属性的变化,如下所示,
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"
}
问题在于,
firebasePhoneVerificationListener.phoneVerificationFailed
在视图模式中被首次触发,
init {
resendVerificationCode()
}
但是对于init {
secondCall()
}
的第二次调用,
firebasePhoneVerificationListener.phoneVerificationFailed
并未在视图模式中触发,我不知道为什么会发生,任何原因或解释都将非常有用。
电流输出:
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
答案 0 :(得分:2)
使用Channel
来接收不同的值。
1)将此添加到您的ViewModel
val _intent = Channel<Intent>(Channel.UNLIMITED)
2)使用报价放置价值
_intent.offer(intentLocal)
3)观察流量
_intent.consumeAsFlow().collect { //do something }
答案 1 :(得分:1)
Pankaj 的回答是正确的,StateFlow
不会两次发出相同的值。正如 documentation 所暗示的:
状态流中的值使用 Any.equals
比较以类似于 distinctUntilChanged
运算符的方式进行合并。它用于将传入更新与 value
中的 MutableStateFlow
合并,并在新值等于先前发出的值时抑制向收集器发出值。
因此,要解决此问题,您可以创建一个包装类并覆盖 equals
(和 hashCode
)方法以返回 false
,即使这些类实际上是相同的:< /p>
sealed class VerificationError {
object Resend: VerificationError()
override fun equals(other: Any?): Boolean {
return false
}
override fun hashCode(): Int {
return javaClass.hashCode()
}
}
答案 2 :(得分:0)
状态流发出的值将被合并,并且不会两次发出相同的连续结果,您可以认为条件检查正在验证旧发出的值不等于新发出的值。
电流输出: 过滤器验证null 筛选失败 过滤器代码为null 筛选成功null 筛选失败ERROR_RESEND 收集失败的错误ERROR_RESEND
(过滤器失败ERROR_RESEND 收集失败的错误ERROR_RESEND)。这是与发出的旧值相同的旧值,因此您不会看到它们被发出。
答案 3 :(得分:0)
合并流后我遇到了类似的问题。 如果使用 == 来判断相等性,则不会执行 emit() 函数。
解决方法:可以包裹一层,重写hashCode()和equals()方法。 equals() 方法直接返回 false。 此解决方案适用于我的代码。联合收割机后的流也发生了变化。
Pankaj 的回答是正确的,StateFlow 不会两次发出相同的值。
在换行之前,即使内容不同,==的结果仍然为真。
答案 4 :(得分:0)
我想我对这个问题有了更深入的了解。首先要确定的是,对于StateFlow,不建议使用变量集合类型(如MutableList等)。因为 MutableList 不是线程安全的。如果核心代码中有多个引用,可能会导致程序崩溃。
之前,我使用的方法是包装类并覆盖equals方法。但是,我认为这种解决方案并不是最安全的方法。最安全的方式是深拷贝,Kotlin 提供的 toMutableList() 和 toList() 方法都是深拷贝。发射方法判断是否有变化取决于equals()的结果是否相等。
我有这个问题的原因是使用emit()的数据类型是:SparseArray
最后,我将类型更改为 SparseArray。虽然增加和删除数据带来了性能损失,但这也从根本上解决了问题。