Although Kotlin doesn't provide a built-in Swift-style solution for property changes observation, you can still do it in several ways depending on what your goal is.
有observable(...)
个委托(in stdlib)允许您处理属性更改.使用示例:
var foo: String by Delegates.observable("bar") { property, old, new ->
println("$property has changed from $old to $new")
}
这里,"bar"
是属性foo
的初始值,每次分配属性后都会调用lambda,以便观察更改.还有vetoable(...)
delegate种方法可以防止这种变化
在实际值更改之前/之后,属性可以使用custom setter执行任意代码:
var foo: String = "foo"
set(value: String) {
baz.prepareToDoTheThing()
field = value
baz.doTheThing()
}
如@KirillRakhman所述,此解决方案非常有效,因为它不会在方法调用和对象中引入任何开销,尽管在有几个属性的情况下代码会有点重复.
通常,您可以实现自己的property delegate,在getValue(...)
和setValue(...)
函数中显式提供属性行为.
To simplify your task, use ObservableProperty<T>
abstract class that allows you to implement delegates that observe property changes (like observable
and vetoable
above) Example:
var foo: String by object : ObservableProperty<String>("bar") {
override fun beforeChange(property: KProperty<*>, oldValue: String, newValue: String): Boolean {
baz.prepareToDoTheThing()
return true // return false if you don't want the change
}
override fun afterChange(property: KProperty<*>, oldValue: String, newValue: String) {
baz.doTheThing()
}
}
为了方便起见,可以编写一个函数来创建委托对象:
fun <T> observing(initialValue: T,
willSet: () -> Unit = { },
didSet: () -> Unit = { }
) = object : ObservableProperty<T>(initialValue) {
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean =
true.apply { willSet() }
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = didSet()
}
然后把lambdas作为willSet
和didSet
传递给它(the default argument代表{ }
).用法:
var foo: String by observing("bar", willSet = {
baz.prepareToDoTheThing()
}, didSet = {
baz.doTheThing()
})
var baq: String by observing("bar", didSet = { println(baq) })
In any case, it's up to you to make sure that the code observing the changes doesn't set the property again as it will likely fall into infinite recursion, or else you might check it in the observing code whether the setter is called recursively.