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 MutableLiveDatainitialUser 都会发生变化。 这是为什么? MutableLiveData的初始值是通过引用传递的吗?我一直认为 Kotlin 是一种“按值传递”类型的语言。

更新: 在将 initUser 复制到 MutableLiveData 之前,问题似乎消失了。

private val _user = MutableLiveData(initUser.copy())

但我仍然不明白为什么我必须这样做。

【问题讨论】:

【参考方案1】:

Kotlin 就像 java,它们是按值传递的。如果您在User 类中实现equals 函数,或者将其设为data class(它隐式实现了equals 函数),它可以确保用户对象的内容被!= 运算符检查.

更新

如果你直接改变LiveData的值,比如这样:

_user.value.name = "some name"

这意味着您正在更改initUsername 属性,因为_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“按引用传递”初始值的主要内容,如果未能解决你的问题,请参考以下文章

java中的参数传递是按引用传递还是按值传递

java中参数传递--值传递,引用传递

java — 值传递和引用传递

JavaScript 是按引用传递还是按值传递语言?

java中的参数传递——值传递引用传递

我应该在哪里更喜欢按引用传递或按值传递?