我有一个包含两个字段的视图,一个用于电子邮件,另一个用于电话号码,我需要验证它们并更新视图上的按钮。
有代码:
@HiltViewModel
class CreateAccountEnterEmailViewModel @Inject constructor(
appData: AppData,
) : ViewModel() {
private var email by mutableStateOf("")
private var phoneNumber by mutableStateOf("")
private var _isPhoneNumberFieldVisibleState: MutableStateFlow<Boolean> = MutableStateFlow(appData.isPhoneNumberRequiredForRegistrationParam.orDef())
val isPhoneNumberFieldVisible: LiveData<Boolean> = _isPhoneNumberFieldVisibleState.asLiveData()
class PairMediatorLiveData<F, S>(firstLiveData: LiveData<F>, secondLiveData: LiveData<S>) : MediatorLiveData<Pair<F?, S?>>() {
init {
addSource(firstLiveData) { firstLiveDataValue: F -> value = firstLiveDataValue to secondLiveData.value }
addSource(secondLiveData) { secondLiveDataValue: S -> value = firstLiveData.value to secondLiveDataValue }
}
}
private val isEmailValid: LiveData<Boolean> =
snapshotFlow { email }
.map { validateEmail(email = it) }
.asLiveData()
private val isPhoneValid: LiveData<Boolean> =
snapshotFlow { phoneNumber }
.map { validatePhone(phone = it) }
.asLiveData()
val isContinueBtnEnabled: LiveData<Boolean> = PairMediatorLiveData(isEmailValid, isPhoneValid)
.switchMap {
return@switchMap liveData {
emit(it.first ?: false && it.second ?: false)
}
}
fun updateEmail(email: String) {
this.email = email
}
fun updatePhoneNumber(phoneNumber: String) {
this.phoneNumber = phoneNumber
}
这个想法是,当用户更新他们的电子邮件或电话号码时,此更新会被中介拦截,该中介根据验证是否通过而提供适当的状态。
但是,出于某种原因,我发现除了调用
updateEmail
或 updatePhoneNumber
方法之外,没有什么可以解决的。我做错了什么?
附注当然,还有订阅视图
isContinueBtnEnabled
。
我看了你的代码,我可以肯定地说,我不能 100% 确定你的逻辑可能有什么问题。只是想提一下。
我看到视图中存在对
isContinueBtnEnabled
的订阅,但我相信 ViewModel
启用“继续”按钮的逻辑可能存在缺陷。我认为 switchMap
块未按预期进行评估。
当我们想要启用“继续”按钮时,
PairMediatorLiveData
和switchMap
转换的错误实现可能会导致逻辑不正确。
也许我们可以通过直接观察电子邮件和电话号码有效性的变化
LiveData
并相应地更新组合有效性状态来简化逻辑,而不是使用自定义PairMediatorLiveData
和switchMap
。
@HiltViewModel
class CreateAccountEnterEmailViewModel @Inject constructor(
appData: AppData,
) : ViewModel() {
private var email by mutableStateOf("")
private var phoneNumber by mutableStateOf("")
private var _isPhoneNumberFieldVisibleState: MutableStateFlow<Boolean> = MutableStateFlow(appData.isPhoneNumberRequiredForRegistrationParam.orDef())
val isPhoneNumberFieldVisible: LiveData<Boolean> = _isPhoneNumberFieldVisibleState.asLiveData()
private val isEmailValid: LiveData<Boolean> =
snapshotFlow { email }
.map { validateEmail(email = it) }
.asLiveData()
private val isPhoneValid: LiveData<Boolean> =
snapshotFlow { phoneNumber }
.map { validatePhone(phone = it) }
.asLiveData()
val isContinueBtnEnabled: LiveData<Boolean> = MediatorLiveData<Boolean>().apply {
addSource(isEmailValid) { emailValid -> // directly observe changes in the isEmailValid
val phoneValid = isPhoneValid.value ?: false
value = emailValid && phoneValid
}
addSource(isPhoneValid) { phoneValid -> // directly observe changes in the isPhoneValid
val emailValid = isEmailValid.value ?: false
value = emailValid && phoneValid
}
}
fun updateEmail(email: String) {
this.email = email
}
fun updatePhoneNumber(phoneNumber: String) {
this.phoneNumber = phoneNumber
}
}
我尝试简化逻辑并确保电子邮件和电话号码的组合有效性状态正确反映在
isContinueBtnEnabled
中。
希望对您有所帮助,或者至少可以为解决您的问题创造一个良好的起点。