基本上我有一个屏幕,并且有一些 EditText
和一个 Button
。
用户必须填写所有字段,否则按钮
将被禁用。
我正在使用 DataBinding 来实现此目的。下面是我在 View 模型中的代码。
val isNextEnabled = MediatorLiveData<Boolean>()
isNextEnabled.apply {
addSource(field1LiveData) {
isNextEnabled.value =
it != null
&& field2LiveData.value != null
&& field3LiveData.value != null
}
addSource(field2LiveData) {
isNextEnabled.value =
it != null
&& field1LiveData.value != null
&& field3LiveData.value != null
}
addSource(field3LiveData) {
isNextEnabled.value =
it != null
&& field2LiveData.value != null
&& field1LiveData.value != null
}
}
在 xml 中
<Button
android:enabled="@{viewmodel.isNextEnabled}"
.
.
.
</Button>
一切都按预期正常工作。但上面的逻辑看起来很麻烦。如果我有更多 EditText
怎么办?编写/维护代码会很痛苦。
有什么办法可以简化它吗?
最佳答案
最终您有一个用例/逻辑,您可以在其中决定何时启用下一步
按钮。
我认为您应该将逻辑分离到有意义的用例中。
例如
// update these when they change in the UI for e.g.
val field1Flow: Flow<Boolean> = flow { ... }
val field2Flow: Flow<Boolean> = flow { ... }
val nextButtonState = combine(field1Flow, field2Flow) { f1, f2 ->
f1 && f2
}.collect { state ->
// use your state.
}
现在...如果您需要特殊逻辑,而不仅仅是两个 bool 代数,您可以随时将其提取到返回更多流的用例中。
或者映射
它或您可以执行的各种操作:
例如
class YourUseCase() {
operator fun invoke(field1: Boolean, field2: Boolean) {
// Your Logic
return field1 && field2
}
}
// And now...
val _nextButtonState = combine(field1Flow, field2Flow) { f1, f2 ->
YourUseCase(f1, f2)
}
val _uiState = _nextButtonState.transformLatest {
emit(it) // you could add a when(it) { } and do more stuff here
}
// And if you don't want to change your UI to use flows, you can expose this as live data
val uiState = _uiState.asLiveData()
请记住,这是在 SO 上编写的伪代码..甚至不是记事本;)
我希望这有点道理。这个想法是将这些位分成用例(您最终可以单独测试)并拥有数据流。当按钮改变状态时,fieldNFlow 会发出值,这会为您触发整个链。
如果您有最新的协程(2.4.0+),您可以使用新的运算符来避免使用 LiveData,但总的来说,我会尝试朝这个方向思考。
最后,带有中介者的 liveData 代码还不错,我至少将“逻辑”提取到 3 个不同的用例中,这样它就不会全部出现在一系列 if/else 语句中。
请注意:我已经超过 3(?) 年没有使用数据绑定(bind)了,我个人不喜欢它,所以我无法告诉您它是否会导致这种方法出现问题。
关于android - 向 MediatorLiveData 添加多个源并更改其值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71480407/