问题描述
用例:一个简单的计费应用。
当数量或价格发生变化时,总数应发生变化。
我正在使用DataBinding,如何通知UI total
已更改?
型号:
class Detail(){
private var _quantity = BigDecimal.ZERO
private var _price = BigDecimal.ZERO
private var _total = BigDecimal.ZERO
var quantity : BigDecimal
get() = _quantity
set(value){
_quantity = value
compute()
}
//same boilerplate for price
private fun compute(){
total = price.mutiply(quantity)
}
}
ViewModel
var instance = Detail()
fun addQuantity(){
instance.quantity.add(1)
}
fun addPrice(){
instance.price.add(1)
}
查看
<button onClick="@{() -> viewModel.addQuantity()}"
<button onClick="@{() -> viewModel.addPrice()}"
<textview text="@{viewModel.instance.total}"/>
我的第一个想法是制作一个LiveData,但是我找不到任何文档说明在模型中创建LiveData属性是一个好主意。据我了解,它们应该专门位于ViewModel中。
我还是尝试了一下,但是发现了另一个问题。我只能使其响应1个属性,但需要响应2个属性(数量和价格)
var quantity = MutableLiveData<BigDecimal>()
var price = MutableLiveData<BigDecimal>()
var total = Transformations.map(quantity){ ... }
var total = Transformation.map(price){ ...} // Duplicate property!
什么是正确的方法?
在.net世界中,您只需调用NotifyPropetyChanged()即可,UI会知道。我在Android中找不到类似的逻辑。
解决方法
我认为您可以按照Google的代码实验室中的指南进行数据绑定。
https://codelabs.developers.google.com/codelabs/android-databinding
简而言之,您可以使用LiveData来更新视图。这样,您的视图模型应该像这样
private val _quantity = MutableLiveData("100")
val quantity = _quantity
xml布局
<data>
<variable
name="viewmodel"
type="myviewmodel.SimpleViewModel"/>
</data>
<TextView
android:id="@+id/quantity_text"
android:text="@{viewmodel.quantity}"
/>
将此添加到活动级别
binding.lifecycleOwner = this
只需按照链接示例获取更多详细信息
,在viewModel中将实例作为LiveData
val instance = MutableLiveData<Detail>()
fun addQuantity(){
instance.value.quantity.add(1)
}
fun addPrice(){
instance.value.price.add(1)
}
在“片段/活动”中,请确保添加此行以进行绑定
binding.lifecycleOwner = viewLifecycleOwner
确保您拥有该库以使用viewLifecycleOwner
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
,
是的,您的直觉是正确的。 LiveData
是ViewModel
的专有内容,但不仅限于ViewModel
。 MVVM体系结构方法建议在LiveData
s中加入ViewModel
。
无论如何,我们假设您有两个实时数据,分别为quantity
和price
。现在,如果total依赖于这两个实时数据,则可以将其设为MediatorLiveData,然后观察这两个属性以确保在(已更改)都可用时,结果始终会得到反映。
下面的示例是您的操作方式:
var quantity = MutableLiveData<BigDecimal>()
var price = MutableLiveData<BigDecimal>()
val total = MediatorLiveData<BigDecimal>().apply {
var updatedQty = 0
var updatedPrice = 0
fun updateTotal() {
this.value = updatedQty.times(updatedPrice)
}
addSource(quantity) { quantity ->
updatedQty = quantity ?: 0
updateTotal()
}
addSource(price) { price ->
updatedPrice = price ?: 0
updateTotal()
}
}