实时数据和 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 中的文本发生更改时,ViewModel
的 liveReviewTitle
属性都会更新。我认为这是通过使用 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 数据绑定:未调用自定义设置器的主要内容,如果未能解决你的问题,请参考以下文章
自定义用户控件的 DependencyProperty 绑定未在更改时更新
angularjs随笔01 数据双向绑定理解 自定义过滤器 时钟更新列子