LiveData“按引用传递”初始值
Posted
技术标签:
【中文标题】LiveData“按引用传递”初始值【英文标题】:LiveData "pass-by-reference" initial value 【发布时间】:2020-12-26 22:06:22 【问题描述】:我有一个看起来像这样的ViewModel
类:
class EditUserViewModel(
private val initUser: User,
) : ViewModel()
private val _user = MutableLiveData(initUser)
val user: LiveData<User>
get() = _user
fun hasUserChanged() = initUser != _user.value
User
可以通过UI更新User数据类实例的一些属性。
要检查从片段导航时是否有任何更改,我使用hasUserChanged
方法。
问题是这总是错误的。我检查了一下,似乎每次更改_user MutableLiveData
时initialUser
都会发生变化。
这是为什么? MutableLiveData
的初始值是通过引用传递的吗?我一直认为 Kotlin 是一种“按值传递”类型的语言。
更新:
在将 initUser
复制到 MutableLiveData
之前,问题似乎消失了。
private val _user = MutableLiveData(initUser.copy())
但我仍然不明白为什么我必须这样做。
【问题讨论】:
【参考方案1】:Kotlin 就像 java,它们是按值传递的。如果您在User
类中实现equals
函数,或者将其设为data class
(它隐式实现了equals
函数),它可以确保用户对象的内容被!=
运算符检查.
更新
如果你直接改变LiveData
的值,比如这样:
_user.value.name = "some name"
这意味着您正在更改initUser
的name
属性,因为_user.value
正是指initUser
所做的对象。因此,!=
运算符总是返回 false,因为我们有一个对象有两个对它的引用。
现在,当你这样做时:
private val _user = MutableLiveData(initUser.copy())
您正在创建initUser
(我们称之为X
)的深层副本,它是内存中的一个新对象,具有与initUser
相同的属性值。
因此,通过更改其属性,例如:_user.value.name = "some name"
,实际上,您是在X
上进行此更改,而不是initUser
。这导致保留initUser
中的初始值,这意味着不要更改它们,并解决问题。
【讨论】:
User
类确实是data class
,所以hasUserChanged
方法可以正确比较它们。但问题是这两个比较值是相同的 - 每次更新 _recipe
值时都会更新 initUser
。
好的,所以如果它是一个数据类,它不介意!=
检查两个具有相同内容的对象的相等性或检查一个对象本身。我想问题是别的。请更改 hasUserChanged
如下,然后检查 logcat 输出:fun hasUserChanged(): Boolean println("initUser: $initUser.toString()") println("_user.value: $_user.value.toString()") return initUser != _user.value
我完全按照你说的做了,这两个对象是一样的,每个值都是一样的。我还使用data binding
在 xml 文件中使用“viewModel.recipe”更新 UI。但我不知道这是否是我的问题的原因。以上是关于LiveData“按引用传递”初始值的主要内容,如果未能解决你的问题,请参考以下文章