android - 向 MediatorLiveData 添加多个源并更改其值

标签 android kotlin android-livedata android-viewmodel mediatorlivedata

基本上我有一个屏幕,并且有一些 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/

相关文章:

android - 如何检查我的应用程序是否在 android 中设置为默认值?

javascript - Webview:window.close 不起作用

java - 以编程方式生成的表行内容的对齐问题

android - 从 Dagger 2 获取空实例

kotlin - Kotlin 中的数据类平等

android - LiveData 适用于回收 View ,但 MutableLiveData 不适用。为什么?

java - 读取时,android 中保存的位图长度为 3 个字节

java - Kotlin 检查列表中已删除类型的元素是否是 Java 类的实例

android - 没有这样的方法错误: No interface method getOrDefault(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; in class Ljava/util/Map;

android - 刷新数据后,RecyclerView 似乎在屏幕上向下移动