实时数据和 2-Way 数据绑定:未调用自定义设置器

Posted

技术标签:

【中文标题】实时数据和 2-Way 数据绑定:未调用自定义设置器【英文标题】:Live Data and 2-Way Data Binding: Custom setter not being called 【发布时间】:2018-11-25 08:18:25 【问题描述】:

我正在使用 2 路数据绑定从我的 ViewModel 中使用 EditText 中设置的字符串更新 LiveData String 对象:

<android.support.design.widget.TextInputEditText
  android:id="@+id/writeReviewTitle"
  android:layout_
  android:layout_
  android:text="@=viewModel.liveReviewTitle"
/>

因此,据我了解,每当 EditText 中的文本发生更改时,ViewModelliveReviewTitle 属性都会更新。我认为这是通过使用 TextWatcher 或图书馆为我处理的某种侦听机制而发生的。我还认为,当需要更新文本时,会调用它的setter似乎并非如此!当文本发生变化时,我需要在我的 ViewModel 中做更多的事情,因此我为liveReviewTitle 实现了一个自定义的setter,但它没有被调用(我尝试过调试)。 这是ViewModel 类中的样子:

var liveReviewTitle: MutableLiveData<String> = MutableLiveData()
        set(value) 
            field = value
            customLogicHere()
        

尝试调试此setter,但它似乎从未被调用!这里发生了什么?感觉有点混乱。文字正在更新中,保存在ViewModel中,只是setter没有被调用。

【问题讨论】:

只要按照这个例子:medium.com/@fabioCollini/android-data-binding-f9f9d3afc761 @NSimon 该示例未使用库提供的真正的 2 路数据绑定。开发人员正在创建侦听器并自行附加它们,这是我想避免的,因为库应该处理这个问题。 【参考方案1】:

当然它从来没有被调用过,你不是在设置一个新的 MutableLiveData,你是在 MutableLiveData 中设置一个新的字符串值(可能是setValue)。

但是,如果您直接公开 MediatorLiveData 而不是 MutableLiveData,您应该能够拦截正在设置的值并在设置值后执行自定义逻辑。

编辑:以下应该按预期工作:

val liveReviewTitle: MutableLiveData<String> = MutableLiveData()
private val mediator = MediatorLiveData<String>().apply 
    addSource(liveReviewTitle)  value ->
        setValue(value)
        customLogicHere()
    
.also  it.observeForever  /* empty */  

【讨论】:

这是有道理的。我不能直接观察实时数据(比如说,在构造函数中),因为我需要一个生命周期所有者,对吧?这就是为什么我需要这个调解人? 当我从 Kotliners conf 回来时。我会写一个示例 @EpicPandaForce 我们还能指望承诺的样品吗?我很好奇:) 我忘了。但是当我放假回家时,我会整理一些东西。明天提醒我,我从来没有找到这个问题XD @Minsky 你不需要清理它我认为因为它被创建一次并与 ViewModel 一起消失,但如果你对此感到恶心,那么你必须存储一个参考我传入的空 lambda,然后在 onCleared() 中删除 that【参考方案2】:

@EpicPandaForce 对您的设置器是正确的,它适用于 MutableLiveData 本身,而不是它所持有的价值。所以你的LiveData应该是val,不需要是var,只要你在绑定上设置LifecycleOwner,框架就应该做正确的事情。您可以将另一个 Observer 添加到您的 LiveData 来代替自定义设置器来添加您的自定义逻辑。

【讨论】:

我无法从视图模型中观察实时数据,因为它不是生命周期所有者。正如接受的答案所建议的那样,将使用调解器! 如果您的内部自定义逻辑不需要了解生命周期,您可以使用observeForever。但是MediatorLiveData 可能是更强大的方法,具体取决于您的用例。 由于调解器也不了解生命周期,因此永远观察可能更容易完成这项工作。 我没有设置绑定的 LifecycleOwner。这解决了它。谢谢!【参考方案3】:

@EpicPandaForce 解决方案是正确的,但在EditText 中,可以以更简单的方式获得两种方式的绑定。 将属性afterTextChanged 添加到您的小部件,如下所示:

android:afterTextChanged="@viewModel::doLogic"

然后在你的ViewModel 类中只写方法:

fun doLogic(s: Editable) //update Livedata or do other logic

编辑

我错过了重要的文档note。更容易(也更合适)的是:

android:text="@=viewModel.someLivedata

然后在我们的 LifecycleOwner 类中,我们可以在需要时随时更新 liveData 的值,当然我们可以对注册观察者的更改做出反应。

【讨论】:

这是最简单最正确的答案。我不敢相信,我读了这么多文件,他们没有提到这一点。总是@ 天啊!!!我花了 2 天的时间试图知道发生了什么,而我的问题是 @ 之后的“=”。谢谢@chitgoks 该死!我也这样做了。伙计们请注意"@=viewModel.someLivedata" 而不是"@viewModel.someLivedata" 我以这种方式使用了两种数据绑定方式并且它工作正常,但是当我在我的片段中观察相同的 LiveData 对象时,观察方法被连续调用,而无需我对 EditText 进行任何更改。这应该发生吗? 我不确定。这种行为可能有几个原因。 '连续调用'到底是什么意思?

以上是关于实时数据和 2-Way 数据绑定:未调用自定义设置器的主要内容,如果未能解决你的问题,请参考以下文章

自定义绑定未触发更新

SAPUI5表格单元自定义控件绑定

自定义用户控件的 DependencyProperty 绑定未在更改时更新

angularjs随笔01 数据双向绑定理解 自定义过滤器 时钟更新列子

asmak 数据包侦听器和自定义 IQProvider 未触发/调用

自定义 WPF 数据绑定:如何添加自定义逻辑?