LiveData“按引用传递”初始值

LiveData "pass-by-reference" initial value

提问人:baltekg 提问时间:9/8/2020 最后编辑:baltekg 更新时间:9/8/2020 访问量:1091

问:

我有一个看起来像这样的类: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 数据类实例的某些属性。
为了检查从片段导航时是否有任何变化,我使用方法。
问题是这总是错误的。我检查了一下,似乎每次我更改_user时都会发生变化.
为什么?的初始值是通过引用传递的吗?我一直认为 Kotlin 是一种“按值传递”类型的语言。
hasUserChangedinitialUserMutableLiveDataMutableLiveData

更新: 在将其放入 .initUserMutableLiveData

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

但对我来说,为什么我必须这样做仍然没有意义。

Android Kotlin 引用 android-livedata 按值传递

评论


答:

1赞 aminography 9/8/2020 #1

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

更新

如果要直接更改 的值,例如:LiveData

_user.value.name = "some name"

这意味着您正在更改 的属性,因为 恰好指的是 所做的对象。因此,运算符总是返回 false,因为我们有一个对象有两个对它的引用。nameinitUser_user.valueinitUser!=

现在,当您这样做时:

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

您正在创建 (我们称之为 ) 的深层副本,它是内存中具有相同属性值的新对象。initUserXinitUser

因此,通过更改其属性,例如:,实际上,您是在 上进行此更改,而不是 。它导致保留 中的初始值,这意味着不要更改它们,并解决问题。_user.value.name = "some name"XinitUserinitUser

评论

0赞 baltekg 9/8/2020
该类确实是 so 方法正确地比较它们。但问题是这两个比较的值是相同的 - 每次更新值时都会更新。Userdata classhasUserChangedinitUser_recipe
0赞 aminography 9/8/2020
好的,所以如果它是一个数据类,它不介意检查具有相同内容的两个对象的相等性或检查对象本身。我想问题出在别的地方。请像以下方式进行更改,然后检查 logcat 输出:!=hasUserChangedfun hasUserChanged(): Boolean { println("initUser: ${initUser.toString()}") println("_user.value: ${_user.value.toString()}") return initUser != _user.value }
0赞 baltekg 9/8/2020
我完全按照你说的做了,这两个对象是一样的,每个值都是一样的。我还使用 xml 文件中的“viewModel.recipe”来更新 UI。但我不知道这是否是我问题的原因。data binding