在Kotlin中,内置了对委托属性(delegated properties)的支持。by机制允许将任何属性的getter/setter委托给特定的对象——委托。最著名的委托有:lazy、observable、vetoable和自定义委托。
优点:
自定义委托示例:
class UpperCaseDelegate { private var value: String = "" operator fun getValue(thisRef: Any?, property: KProperty<*>): String = value operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) { value = newValue.uppercase() } } class Person { var name: String by UpperCaseDelegate() }
限制:
可以在伴生对象或顶级对象的属性中使用需要访问上下文的委托(例如Android上下文)吗?
常常有人错误地回答 "当然可以,为什么不呢?"
正确答案: 不可以,因为伴生对象和顶级对象在类或应用的实例化之前进行初始化,这可能会导致访问未初始化的上下文时出现错误。需要访问实例的委托应仅用于类的属性。
故事
在Android ViewModel中委托惰性初始化:程序员将heavy-lazy委托放在伴生对象中。在某些情况下(SDK更新后),应用在初始化时崩溃——上下文尚不可用,而委托已执行其"init"。
故事
委托的错误序列化:使用自定义委托存储数据,但它包含对上下文的不可序列化引用。尝试序列化时出现错误并丢失数据。
故事
带有回调错误的可观察委托:开发者使用Delegates.observable来控制状态,在lambda内部赋值新值,导致运行时循环和StackOverflowError。